API Reference
The full Embed SDK surface — Embed.render, Embed.init, the instance handle, the declarative data-embed form, and event names.
The loader defines one global, Embed. TypeScript declarations ship at embed.d.ts next to the loader.
Embed.render(product, options)
Mounts a surface and returns an instance, or null if it can't mount (missing required option, target not found, unknown product). The reason is logged to the console.
var instance = Embed.render("chatbot", {
target: "#embed",
chatbotId: "cb_123",
authToken: "<jwt>",
});product — one of "chatbot", "template", "broadcast", "broadcastList", "teamChat". Get the list at runtime with Embed.products().
options — the common options plus any surface-specific options:
| Surface | Extra options |
|---|---|
chatbot | chatbotId (required) |
broadcast | fromBroadcast, statuses, redirectUrl (all optional) |
broadcastList | showCreateButton (optional) |
teamChat | agentId (optional) |
template | — |
Instance
The object returned by render. Also exposed as element._embed on declaratively-mounted elements.
| Member | Signature | Description |
|---|---|---|
product | string | The surface name this instance was created for. |
iframe | HTMLIFrameElement | The mounted iframe. |
on | (type, handler) => instance | Subscribe to an event. Chainable. |
once | (type, handler) => instance | Subscribe for a single firing. |
off | (type, handler?) => instance | Remove a handler, or all handlers for type when omitted. |
send | (type, payload?) => instance | Post a message to the iframe (forward-compatible; consumed where supported). |
destroy | () => void | Remove the iframe and detach all listeners. |
instance
.on("saved", function (m) {})
.once("ready", function (m) {});
instance.off("saved"); // remove all "saved" handlers
instance.destroy(); // tear downEmbed.init(root?)
Scans root (default: document) for [data-embed] elements and mounts any not yet initialized. Returns the array of instances created. Runs automatically on DOM ready; call it manually after inserting embed markup dynamically (SPAs). It's idempotent — already-mounted elements are skipped.
Embed.init(); // scan the whole document
Embed.init(containerEl); // or just a subtreeEmbed.products()
Returns the surface names accepted by render, e.g. ["template", "broadcast", "broadcastList", "chatbot", "teamChat"].
Embed.version
The loader version string, e.g. "1.0.0".
Declarative mounting
Mount with markup and zero render code. The loader scans for [data-embed] on DOM ready (and via Embed.init) and mounts each element.
<div
data-embed="chatbot"
data-chatbot-id="cb_123"
data-auth-token="<jwt>"
data-theme="system"
style="height: 720px"
></div>Every data-* attribute maps to an option (the browser camel-cases dataset keys):
| Attribute | Option |
|---|---|
data-embed | the product (first arg to render) |
data-api-key | apiKey |
data-auth-token | authToken |
data-theme | theme |
data-base-url | baseUrl |
data-chatbot-id | chatbotId |
data-agent-id | agentId |
data-from-broadcast | fromBroadcast |
data-statuses | statuses |
data-redirect-url | redirectUrl |
data-show-create-button | showCreateButton |
The mounted instance is available as element._embed.
Events as DOM CustomEvents
Declaratively-mounted surfaces re-emit every event as a DOM CustomEvent named embed:<event> on the host element, with the payload in event.detail. This lets a page listen the same way for every surface:
<script>
var el = document.querySelector('[data-embed]');
el.addEventListener("embed:ready", function (e) {
console.log(e.detail);
});
el.addEventListener("embed:published", function (e) {
console.log(e.detail);
});
</script>Event names by surface
| Surface | Events (besides ready) |
|---|---|
chatbot | saved, published |
template | created, cancelled |
broadcast | created, cancelled |
broadcastList | — (only ready) |
teamChat | messageSent, messageDelivered, messageIncoming, conversationChanged |
ready fires for every surface. As DOM CustomEvents these are prefixed embed: (e.g. embed:saved).
Security model
- Pass one of
apiKey/authToken;authTokenwins when both are set. Prefer a short-livedauthTokenin browser contexts — see the auth note. - The loader sends your page origin to the iframe as
parentOrigin. The surface only posts events back to that exact origin (never*), so payloads can't leak to another frame. - Inbound events are filtered by source iframe and origin before dispatch, so multiple embeds on one page stay isolated.
How is this guide?


