Channels & embed
Publish an agent as a widget, a page, or an iframe — themed, embedded, and signed in.
Channels are where people reach an agent. Each agent has two publish surfaces,
toggled independently: a floating widget bubble for customer sites, and
a full-screen page at a public chat URL.
Publishing
An agent's Channels page walks through four steps with a live preview: Identity & Avatar, Channel Mode (toggle each channel and edit its settings), Greeting, and Theming. The greeting is agent-level, shared by both surfaces.
Widget settings
| Setting | Values |
|---|---|
Bubble icon (buttonIcon) | Circle, Square, Bot, Help, Sparkles, or an uploaded image (1 MB max) |
Bubble style (launcherStyle) | flat (default), sphere, or animated — the editor offers Flat and Ambient sphere (animated) |
Attention message (attentionMessage) | Text shown above the bubble while the widget is closed. Blank hides it. |
Page settings
| Setting | Values |
|---|---|
Page title (pageTitle) | The browser tab title. Defaults to the agent name. |
Favicon (favicon) | A URL or an uploaded image (1 MB max). |
URL path (path) | 2–63 lowercase letters, digits, and single inner hyphens. Capitals are lowercased; an id-shaped value is refused. |
The public URL is /chatbot/{org}/{path}; with no path it falls back to the
agent id. /chatbot/{org} alone is the organization's chat page, with a picker
over every agent whose page channel is on. A disabled page channel's URL 404s
rather than showing a dead chat.
Theming
Theming is organization-wide: one theme styles every agent's widget, page, and preview. It's edited in step 4 of any agent's Channels page, and saving applies it to the whole org.
| Field | Range |
|---|---|
| Chat background, sidebar background, text, borders, brand, and bot-bubble colors | Any color |
| Loading animation | Three dots (default) or spinner |
| Font family | System default or a preset stack |
| Font size | 8–40 px |
| Corner roundness | 0–24 px |
Over the API it's GET /appearance (agent:read) and PATCH /appearance
(agent:update). Until the organization saves a theme, an agent that still
carries old per-agent theming keeps being served it.
Embedding
The widget ships as a script tag or an iframe; the page channel as an iframe. Every snippet is on the Channels page under Embed & integration.
Script. Loading widget.js?agentId=<id> mounts the widget on its own.
Call AssivyWidget.init(options) instead for control:
| Option | Meaning |
|---|---|
agentId | The agent to load. |
sessionToken | An SSO session token (below). Without one, the visitor chats anonymously. |
apiBaseUrl | The API to call, when it isn't on the script's host. |
position | bottom-right (default) or bottom-left. |
buttonSize | default, sm, or lg. |
open | Start with the chat open. |
enableRecentChats | Show the visitor's past conversations. Default on. |
onToolResult, onWidgetEvent | Callbacks for the host events below. |
hostMethods | Methods the agent's browser tools may call on your page with runtime.host.call(name, params). |
AssivyWidget.destroy() removes the widget and its styles.
Iframe. Any site may frame /chatbot pages. The page channel frames the
full chat; the widget channel frames the corner widget at the page URL plus
?view=widget, which asks its host to resize the frame with
assivy:widget.layout messages. Frames run sandboxed with clipboard,
microphone, and geolocation permissions.
Three settings per channel gate the postMessage bridge between frame and host — not framing itself:
- Allow iframe embedding — needed for any message, including the iframe widget's resize requests.
- Enable parent-frame messaging (
parentApiEnabled) — on by default. Needed for events, host commands, and browser tools calling the host. - Allowed origins — the parent origins the frame talks to. An empty list allows any parent, so a real embed should set it.
Host events
The chat tells the host page what happened:
| Event | When |
|---|---|
assivy:chat.ready | The framed chat loaded. |
assivy:chat.resize | The framed chat's content height changed. |
assivy:chat.tool_result | A tool call finished — every tool reports; filter by toolName. |
assivy:widget.event | A widget in the chat called emitEvent(name, payload). |
assivy:widget.layout | The iframe widget needs a new frame size. |
The script widget dispatches the tool and widget events on window (read
event.detail) and passes them to the init callbacks; iframes post them to
the parent. Treat their contents as input, not instructions.
Host commands
The page can drive the chat: AssivyWidget.open(), close(), and
sendMessage(text, { context }), which opens the chat and sends up to 4,000
characters as the visitor. context is a small object (up to 4 KB) the agent
reads as data, shown to the visitor as a chip. Iframes take the same commands
as { type: 'assivy:host.command', command, text, context } postMessages
(command is open, close, or send_message), under the same bridge rules.
SSO
To chat as your site's signed-in user instead of an anonymous visitor, mint a session from your backend. The route is served by the web app's host, not the API's:
POST /api/auth/sso/session
X-API-Key: <your API key>
Content-Type: application/json
{ "externalUserId": "123", "email": "ada@example.com", "organizationId": "<org id>", "name": "Ada" }externalUserId, email, and organizationId are required, and the
organization must be the API key's own. Profile fields such as name and
language are saved on the user; anything else goes to its metadata. The
response's token goes to the widget as sessionToken in
AssivyWidget.init, or to a hosted page as ?ssoToken=. SSO users join the
organization as guests.
Anonymous visitors
Public surfaces chat without an account, but not without rules: anonymous
visitors receive capabilities shared public plus those with no sharing of
their own (which inherit the agent's audience) — anything restricted is
withheld, and the UI warns when a restricted item sits on a published agent.
Visitors never receive the agent's instructions, tool configs, turn hooks, or
schedule. Memory writes require an owner, and anonymous feedback inherits the
thread's tenant so it stays visible to scoped reads.