Install the embed
The embed is a single script served from https://app.roxels.ai/embed.js. It's unversioned and loaded live — once you include it, every fix and improvement ships automatically.
The three install styles
Pick the one that matches your control needs.
Style 1: One script tag, autoinit
The simplest path. The script reads its own data-* attributes and initializes itself. Roxels renders a floating button; the user clicks it to start.
<script src="https://app.roxels.ai/embed.js" data-template-key="rk-your-embed-key"></script>Optional data-* attributes:
<script
src="https://app.roxels.ai/embed.js"
data-template-key="rk-your-embed-key"
data-person-name="Ada Lovelace"
data-external-id="user_123"
data-view="checkout"
></script>data-person-name— Display name for the participant (passed to the agent).data-external-id— Your stable identifier for this user (returned inonComplete, used for session resumption).data-view— Page identifier used by the persistent launcher's visibility rules.
Style 2: Manual init
You control when initialization happens — useful for SPAs that mount the embed after a route change, or when you want to pass callbacks.
<script src="https://app.roxels.ai/embed.js"></script>
<script>
Roxels.init({
templateKey: "rk-your-embed-key",
personName: "Ada Lovelace",
externalId: "user_123",
onComplete: (results) => {
console.log("Conversation complete:", results);
},
onUnderstanding: (data) => {
console.log("Goal data captured:", data);
},
onClose: () => console.log("widget closed"),
onError: (error) => console.error("widget error:", error),
});
</script>After init, the floating button appears (if the template has a persistent launcher configured). The user clicks it to open a conversation.
Style 3: Programmatic start
You skip the floating button entirely and call start() whenever you want. Best for triggering conversations from your own UI — a button you control, a form submission, a route transition.
<script src="https://app.roxels.ai/embed.js"></script>
<script>
document.querySelector("#start-call").addEventListener("click", () => {
const call = Roxels.start({
templateKey: "rk-your-embed-key",
display: "modal",
personName: "Ada Lovelace",
externalId: "user_123",
});
call.on("complete", (results) => {
console.log("done:", results);
});
});
</script>For full headless control (no UI from Roxels at all), use display: "none" and read Headless mode.
Init options
These can be passed to Roxels.init(), Roxels.start(), Roxels.open(), or set as data-* attributes (kebab-case).
| Option | Type | Description |
|---|---|---|
templateKey |
string | Your rk_… embed key. Required unless you pass sessionId. |
sessionId |
string | An existing session id (server-side created). Skips template-key session creation. |
personName |
string | Display name for the participant. |
externalId |
string | Your stable identifier for this user. |
view |
string | Page identifier used by launcher visibility rules. |
display |
"modal" | "compact" | "none" |
Presentation. Defaults to "modal". |
onUnderstanding |
function | Called on each goal-data update. |
onComplete |
function | Called when the conversation finishes with the final result. |
onClose |
function | Called when the widget closes (any reason). |
onError |
function | Called on any embed-level error. |
onGoalTransition |
function | Called when a goal commits or the active goal changes. |
fabAnchor |
string | HTMLElement | CSS selector or element to anchor the floating button to. |
fabContainer |
string | HTMLElement | Container element for the floating button. |
Server-side session creation
If you want to create the session in your backend (more control, no embed key on the client), use the REST API to create a session, then pass the sessionId to the embed:
<script src="https://app.roxels.ai/embed.js"></script>
<script>
// sessionId came from your backend
Roxels.start({ sessionId: "sess_abc123", display: "modal" });
</script>This path uses your server's bearer token (sk_…) to create the session and never exposes a publishable key to the browser. Useful when you want to encode trusted context into the session before the user joins.
Domain allowlisting
Embed keys are scoped to the origins you whitelist when you create the key. If your page is at https://example.com and your key isn't allowlisted for that domain, the session-creation call fails. Allowlist all origins where the widget runs (production, staging, http://localhost:3000 during dev).
Read next
- Persistent launcher — Configure the floating button (position, visibility rules, anchor, label).
- Display modes — Modal vs compact behavior, sizing, lifecycle.
- Headless mode — Run the call with your own UI. The deep page for engineers integrating Roxels into a custom voice product.
- JS API reference — Every controller method.
- Events — Every callback / event payload.
- Microphone permissions — Required host config so the iframe can use the mic.
- Identity and resumption — How
externalIdflows and when to verify identity server-side.