Components
The Quickstart uses your own connection button and redirects the user to the hosted flow. Use Configure components to embed that flow in your app.
https://configure.dev/js/configure.js provides the Configure.* functions. https://configure.dev/components/configure-components.global.js defines the web components. Include each required script once per page.
publishableKey is your pk_ key, safe in the browser, and agent is your agent handle. Both come from npx configure setup --users. displayName is what the user reads; agent is the identity every approval and token is bound to.
Composer button
Use the composer button in a chat interface. Its + menu includes a Personalization option that opens the hosted flow inline. Set linkEl to mount the flow in a dismissible panel in the assistant message area.
html
<script src="https://configure.dev/js/configure.js"></script>
<div id="configure-entry"></div>
<div id="configure-link-host"></div>
<script>
Configure.personalizationButton({
el: "#configure-entry",
linkEl: "#configure-link-host",
publishableKey: "pk_...",
agent: "your-agent",
displayName: "Your App",
theme: "light", // or "dark"; omit it and the script warns and follows the system
onImage: () => openImagePicker(),
onFile: () => openFilePicker(),
});
</script>Allow the flow container to use the full width of the assistant message area. A 420px maximum width is too narrow for the hosted flow.
Your own button
Use your app's existing button style for a custom connection button. Link it to the server route that starts the hosted flow. Configure redirects the user to your callback afterward. Follow Quickstart steps 2 through 5.

html
<a class="chip" href="/configure/start">Connect</a>The route creates a connection URL with returnUrl and redirects the user to it. profileFor is the handle from the Quickstart, and RETURN_URL is your callback route's https address, a constant:
ts
const RETURN_URL = "https://yourapp.com/configure/return";
app.get("/configure/start", async (req, res) => {
const connect = await profileFor(req.user.id).connect({ returnUrl: RETURN_URL });
res.redirect(connect.connect_url); // Configure's page, then back to RETURN_URL
});Configure redirects the user to your callback route: Quickstart, step 5.
Integration button
Use the integration button in settings or an integrations list. The component renders a Connect or Manage control that opens the hosted flow.
html
<script src="https://configure.dev/js/configure.js"></script>
<script src="https://configure.dev/components/configure-components.global.js"></script>
<configure-personalization-button
variant="integration"
external-id="user_123"
></configure-personalization-button>variant is menu, the composer button above as a raw element, or integration. With manual the element announces its events and never opens the flow, which is how the demos on this page run.
Hosted link
Use Configure.link() to mount the hosted flow in a container you select. Handle its completion event to receive the token. It uses the same authorization flow as the composer and integration buttons.
html
<script src="https://configure.dev/js/configure.js"></script>
<div id="configure-link"></div>
<script>
Configure.link({
el: "#configure-link",
publishableKey: "pk_...",
agent: "your-agent",
displayName: "Your App",
theme: "light",
onEvent: (event) => {
if (event.type === "configure:linked") {
// event.payload = { token, userId, tokenUse }
sendTokenToYourBackend(event.payload.token);
}
},
});
</script>Configure.link() returns a frame handle, not the token. The token arrives in configure:linked, through onEvent or as a DOM CustomEvent on the mount element. Send it to your server and use it there with configure.profile({ token }).
Connected
The composer button updates its state when the hosted flow completes on the page. After reloads, or for a custom button, use the profile context cached by your server to determine the connection state.
ts
// The refresh in Quickstart step 6 stores { text, refreshedAt }. text is null until the user connects.
const stored = await store.get(user.id);
const label = stored?.text ? "Connected" : "Connect";Render the state from the cached Configure response and refresh it daily. This avoids a profile request on each page load. Do not infer connection status from browser events alone.
Approval card
Use the approval card to confirm email sends and calendar event creation. It displays the tool and its parameters. If the user does not respond before the timeout, it denies the action. The card emits an event with the decision.
html
<configure-tool-approval
action-id="call_123"
tool="configure_email_send"
timeout-seconds="60"
></configure-tool-approval>
<script>
const card = document.querySelector("configure-tool-approval");
card.params = { to: "sam@example.com", subject: "Intro" }; // a property, not an attribute
card.addEventListener("configure:tool-approve", (e) => runTool(e.detail.actionId));
card.addEventListener("configure:tool-deny", (e) => skipTool(e.detail.actionId));
</script>configure:tool-always-allow fires when the user approves future calls to that tool. Your app must store and apply that preference.
Attributes
On the raw <configure-personalization-button>:
| Attribute | Default | What it does |
|---|---|---|
variant | menu | menu or integration |
external-id | Your user ID, used to associate the connection with the profile your server reads | |
connectors | Which apps the flow offers, comma separated | |
personalization-label | The text of the Personalization row | |
placeholder | Placeholder text in the composer slot | |
manual | false | Announce events only; never open the flow |
hide-images, hide-files | false | Remove the image or file rows from the + menu |
image-label, file-label | Text of the image and file rows | |
max-visible | How many recent items the menu lists | |
show-actions, show-settings | Show the actions row and the settings row |
Events the element announces: configure:personalization-open and configure:personalization-toggle as the flow opens and closes, configure:personalization-menu-toggle for the + menu, configure:linked when the link completes, configure:image-select and configure:file-select for the attachment rows, and configure:settings-press.
The buttons support keyboard navigation and visible focus states. They fit a 375px-wide viewport.