Embedding the widget¶
The fastest way to put a live AiFlow agent on your website is a single
<script> tag. It drops a floating chat launcher onto the page; visitors
who click it get a voice or text conversation with the agent you specify,
no further integration work required.
The drop-in embed¶
<script
src="https://api.your-domain.com/widget/aiflow-widget.js"
data-agent="support-bot"
data-api-base="https://api.your-domain.com"
></script>
data-agentis the target agent'sslug, not its numeric ID or display name. See Agents & channels for how slugs work.data-api-baseis your deployment's base URL, the samehttps://api.your-domain.comused everywhere else on this site.
That's it. Add the tag to any page and a launcher button appears, docked to
the bottom-right corner by default. If your site already has something
else anchored there, a cookie banner, another chat widget, add
data-position to dock it bottom-left instead:
<script
src="https://api.your-domain.com/widget/aiflow-widget.js"
data-agent="support-bot"
data-api-base="https://api.your-domain.com"
data-position="bottom-left"
></script>
Voice vs. text mode¶
When a visitor opens the widget, they choose voice or text. Either can be switched to the other at any time during the conversation.
- Voice mode starts listening immediately, with no separate "start talking" click, and supports live interruption: the visitor can talk over the agent mid-response (barge-in), the way a phone call works. From voice mode, the visitor can also turn on their camera or share their screen; the video feed layers onto the live audio channel so the agent can see and describe what it's looking at. Video alone, without an active audio channel, never triggers a response on its own.
- Text mode is a plain typed conversation with streamed replies. No microphone access is ever requested in this mode.
- Attaching a file, in either mode, is a separate, opt-in-per-agent
control (see
allow_file_uploadabove): a visitor can attach a photo, receipt, spreadsheet, slide deck, or document mid-conversation. A JPEG or PNG is sent the same way a screen-share frame is, straight into the live video channel. Anything else is turned into text first, either by extracting it directly or, for a scanned page or a broader photo format with no text to extract, by describing it with a one-shot vision-capable call, and then joins the conversation exactly like a typed message. Supported types:.txt,.md,.csv,.json,.xml,.yaml/.yml,.log,.html/.htm,.pdf,.docx,.xlsx,.pptx,.jpg/.jpeg,.png,.gif,.webp,.heic/.heif.
Access control¶
By default, any website can embed any agent's widget, and any visitor can start a session. Two independent controls narrow that down; an admin sets both on the agent itself, which is outside the scope of this site since agent configuration is an admin-dashboard concern:
- Allowed origins. An agent can be restricted to a list of origins
(
allowed_origins). A session request from a page whose origin isn't on that list is rejected. - A site key. An agent can require a site API key on top of origin
restriction. Pass it as
data-site-keyon the script tag, or as anX-Site-Keyheader if you're talking to the REST API directly (see below).
<script
src="https://api.your-domain.com/widget/aiflow-widget.js"
data-agent="support-bot"
data-api-base="https://api.your-domain.com"
data-site-key="your-site-key"
></script>
A rejected origin or a missing or invalid site key comes back as a 403
or 401; see Errors & rate limits for the
response shape.
Building a custom client¶
The drop-in script above covers most integrations. If you're building
your own front end instead, say a custom mobile app, or a framework
where injecting a raw <script> tag is awkward, you'll make the same
three calls the bundled widget makes internally.
1. Fetch the agent's public config¶
GET /api/v1/agents/{slug}/widget/config is public and unauthenticated. It
returns just enough to render a launcher before a session exists:
{
"slug": "support-bot",
"name": "Support Bot",
"greeting_instruction": "Greet the caller warmly and ask how you can help.",
"brand_primary_color": null,
"brand_accent_color": null,
"require_identity": false,
"allow_file_upload": false
}
This endpoint doesn't check origin or a site key; it's meant to be safe
to call from anywhere before a session is created. brand_primary_color
and brand_accent_color are deployment-wide, not per-agent (see
White-labeling): they're non-null once an Owner or
Admin sets them in Settings → Branding. The drop-in embed
(aiflow-widget.ts) already applies them as the launcher and panel's
default accent automatically; a custom client built against this
endpoint directly would need to apply them itself the same way, by
setting --af-accent and --af-accent-2 on whatever element hosts the
widget's styles. require_identity and allow_file_upload are both
per-agent toggles an Owner or Admin sets on the agent itself: the
former gates the pre-session contact form, the latter shows or
hides the file-attach control described below.
2. Create a session¶
POST /api/v1/agents/{slug}/widget/session creates a session and returns a
short-lived token used to open the live connection. visitor_name and
visitor_email are both optional. If your page already knows who's
visiting, a logged-in user, for example, passing visitor_email also
enables cross-session lookback, if the agent has that turned on, so it
can recall its last conversation with the same person.
This is the request that the origin and site-key checks above apply to.
const response = await fetch(
"https://api.your-domain.com/api/v1/agents/support-bot/widget/session",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Site-Key": "your-site-key",
},
body: JSON.stringify({
visitor_name: "Jane Doe",
visitor_email: "jane@example.com",
}),
},
);
const session = await response.json();
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"session_id": "3f9a1b2c4d5e6f708192a3b4c5d6e7f8",
"expires_in": 300
}
token is short-lived (expires_in seconds, 300 by default) and is only
valid for opening the WebSocket connection below, not as a general-purpose
API credential.
Session creation is rate-limited
Like event ingestion, widget session creation is rate-limited per
client IP to protect your deployment from a scraping bot or a
misbehaving page. Legitimate traffic shouldn't come close to the
limit; see Errors & rate limits for
what a 429 looks like.
3. Open the live session¶
WS /api/v1/agents/{slug}/widget/ws?token=<token>&mode=voice|text is the
live connection itself: audio or text streaming in both directions for
the duration of the conversation. token is the value from step 2, and
mode selects voice or text for that connection, matching whichever
mode the visitor picked in the UI. There's no REST or cURL equivalent for
a WebSocket. This is the same endpoint the bundled aiflow-widget.js
script connects to internally, so most integrations won't need to speak
this protocol directly unless they're replacing the widget UI entirely
with a custom one.