Web Chat Widget
Embeds a chat bubble on a website, backed by an agent flow. Unlike the other channels there's no external provider involved: the widget is a NeuraFlow script tag plus a per-widget config record.
1. Prerequisites
None. No external account or portal is required; the widget is served from NeuraFlow itself.
2. Configuration
/channels/chat-widgets lists widgets. Each row has an enabled toggle
(calls PATCH /chat-widgets/{id} with just { enabled }, no confirmation),
a Get embed code action, and a delete action (confirmation dialog "Are
you sure?", then DELETE /chat-widgets/{id}). Get embed code shows:
<!-- NeuraFlow Chat Widget -->
<neuraflow-bot agent-id="{widget_id}" core-url="{CORE_URL}"></neuraflow-bot>
<script src="{origin}/chat-widget.js" async></script>
/channels/chat-widgets/create and /channels/chat-widgets/{widgetId}/edit
render the same full-page editor: two tabs on the left (General,
Security), a live preview of the actual widget on the right that updates
as you type, and Cancel / Create Widget (Update Widget when
editing) in the page header. There's no per-tab save, the button submits the
whole form; Create Widget/Update Widget validates every field across
both tabs (Zod), and a failed check anywhere shows a generic "Please fix the
form errors before submitting" toast plus inline messages under the specific
fields. On success it calls POST /chat-widgets (create) or
PATCH /chat-widgets/{id} (edit), toasts "Chat widget created
successfully!" / "Chat widget updated successfully!", and for create,
navigates to the edit page for the new widget.
General tab
Basic Information: Widget Name (required, "Widget name is required"), Bot Name (optional, falls back to Widget Name in the chat header if empty), Description (optional, max 500 chars, shown on the widget's list card), Input Placeholder (required, "Placeholder text is required"), Welcome Message (required, "Welcome message is required"), Agent Flow (optional select, "None (Use default chat)" is a real selectable option, not just a placeholder), Persona (Friendly / Professional / Custom, switching away from Custom clears the custom prompt), Custom Persona Prompt (shown only when Persona is Custom), Widget Enabled toggle.
Launcher & Icon: Button Title and Button Description (both optional,
free text shown on the floating launcher button). Upload Icon is a file
picker, not an upload to the server: it's read client-side and stored as a
base64 data URL directly in the widget's logoUrl field on save, capped at
500KB ("Image size must be less than 500KB", checked before the file is
even read). Once an icon is set, three toggles appear: Show in Header, Show
in Toggle Button, Use as Agent Avatar. Two more toggles are always visible
regardless of icon state: Show Bot Icon (default icon next to messages) and
Show Message Actions (feedback/copy/resend buttons on messages).
Behavior: Minimized Bar, Picture-in-Picture on Tab Switch, Unread Notifications, all independent toggles, no fields.
Styles: Placement offers only Bottom Right and Bottom Left in
the dropdown, even though the underlying position field also accepts
top-right and top-left, there's no UI path to set those two. Every
other row here is a colour picker (native swatch plus a synced hex text
input, must match #RRGGBB or the field shows "Must be a valid hex color"),
a 0-50px radius slider, or a shadow dropdown (None / Small / Medium / Large
/ Extra Large / 2x Large), grouped by element:
| Element | Colour(s) | Radius | Shadow |
|---|---|---|---|
| Chat sheet | Sheet Color | Sheet Radius | Shadow |
| Toggle button | Chat Toggle Color, Toggle Text/Icon Color | Chat Toggle Button Radius (0-100px) | Chat Toggle Shadow |
| Agent (bot) messages | Background Color, Text Color | Agent Radius | Agent Shadow |
| User messages | Background Color, Text Color | User Radius | User Shadow |
| Message input | Text Color, Border Color | none | none |
| Header | Header Color, Header Text Color, Action Button Color | Header Blur Effect (0-50, a backdrop blur intensity, not a corner radius) | Header Shadow |
"Action Button Color" is a misleading label: it writes to the widget's
headerIconColor style field, not to any button-specific field. The schema
also carries a sendButtonBackground style field that this tab never
exposes a control for at all, it can't be set from the UI.
Voice Settings: Enable Voice toggle, disabled and forced off if voice is
turned off globally for your account (Settings → Display), with a banner
explaining that. When on, Speech-to-Text Model (Deepgram Nova 3/2/Enhanced/
Base, or OpenAI Whisper) and Text-to-Speech Model (five Deepgram Aura
voices, six OpenAI voices) appear. Regardless of what's selected here, the
editor forces voiceEnabled to false and both provider fields to null
at submit time if voice is globally disabled for your account, the toggle
being visually on doesn't survive save in that state.
Terms & Conditions: Enable Terms & Conditions toggle; when on, Terms Content (markdown, textarea), Accept Button Text and Decline Button Text (both default to "I Accept" / "Decline" via placeholder, not enforced defaults) become editable, greyed out otherwise.
Security tab
Widget Token: a read-only field, pre-filled with a random UUID
generated in the browser the moment you open the create page, not fetched
from the server. If it's ever empty, a Generate Token button appears
and calls POST /chat-widgets/utils/generate-token. Once a value exists
(always, in practice) the button becomes Copy (clipboard) and
Regenerate Token (same endpoint), plus a warning that regenerating
invalidates the old token as soon as you save.
Allowed Domains: a text input plus Add button (also triggered by
Enter), client-side validated against a domain-shaped regex or the literal
string localhost ("Please enter a valid domain name"), duplicates rejected
("Domain already added"). Each added domain is a removable badge. Empty
list is explicitly labelled "No domains restricted. Widget will work
anywhere."
Rate Limiting: Enable Rate Limiting toggle; when on, a Requests per Minute slider (1-120) appears, labelled "Maximum number of requests allowed from a single IP/Session in 60 seconds."
Identity Verification (HMAC): a "Developers Only" warning card, then
Enforce Identity Verification toggle and HMAC Secret Key, same
generate/copy/regenerate pattern as Widget Token, calling
POST /chat-widgets/utils/generate-secret.
3. Other
The three Security tab controls are independently opt-in and backward compatible: an empty Allowed Domains list allows every origin, no Widget Token means the token header is never checked, and rate limiting is off unless explicitly enabled. A widget with nothing configured on the Security tab has none of these protections.
GET /chat-widgets/{widget_id} (used to load the widget on the embedding
page) and POST /chat-widgets/{widget_id}/session-token (used to obtain the
short-lived JWT the widget uses for chat calls) are both public endpoints,
no NeuraFlow auth required, and only return data for enabled widgets.