Embedding the Widget
How to add the Chat9 chat widget to your site, with optional userHints for personalization.
Basic embed
Paste this snippet before the closing </body> tag:
data-bot-id is your bot's public ID — safe to include in page HTML.
Loading widget.js registers window.Chat9Widget but does not mount any UI. You explicitly start the widget with Chat9Widget.start(config?) — call it with no arguments for an anonymous widget with default styling, or pass an options object to customize.
Do not add
asyncordeferto thewidget.jstag — the loader readsdocument.currentScriptsynchronously and will not register without it.
Configuration
All options are arguments to Chat9Widget.start():
| Field | Default | Notes |
|---|---|---|
mode | "bubble" | "bubble" or "inline" |
target | — | DOM element id for inline mode |
color | violet gradient | Bubble background color (#RGB, #RRGGBB) |
position | "right" | "right" or "left" |
topClearance | 0 | px reserved at the viewport top (e.g. height of a fixed navbar) |
userHints | — | See userHints |
Modes:
- Bubble — floating button, bottom corner of the page.
- Inline — renders inside a container you provide. Add
<div id="chat9-widget"></div>where you want the widget.
Routing from Russia
If your site primarily serves visitors in Russia, load the widget from the Russian edge proxy. Replace widget.getchat9.live with widget-ru.getchat9.live in the script src — both the widget bundle and the API origin route through it automatically:
This bypasses traffic throttling that some Russian ISPs apply to Vercel/Railway. Visitors outside Russia work the same way — they just hit the RU edge with a small extra hop. If you serve mixed audiences, detect the visitor's country server-side and emit a different src per request, or A/B test.
CSP
If your site uses a Content Security Policy, default origins:
If you load the widget from the Russian edge proxy (widget-ru.getchat9.live), allow these origins instead:
Where to get the embed code
- Log in to your Dashboard at https://getchat9.live.
- Copy the embed block from the Dashboard home or the Embed page.
Lifecycle API
window.Chat9Widget exposes an explicit lifecycle. The script downloads once; you control when the chat appears, when it goes away, and what identity it carries.
| Method | Behavior |
|---|---|
Chat9Widget.start(config?) | Mount the FAB and chat iframe. No-op (with a console warning) if already started — call stop() first to reconfigure. |
Chat9Widget.stop() | Unmount the DOM and listeners. window.Chat9Widget stays registered; the script does not re-download. Call start() again to bring it back. |
Chat9Widget.setHints(hints | null) | Push a new identity into a running widget. If the widget is stopped, the hints are remembered for the next start(). Pass null to clear (anonymous). |
Chat9Widget.isStarted() | true while the widget is mounted. |
Chat9Widget.destroy() | Terminal teardown. Removes the DOM and deletes window.Chat9Widget. To use the widget again on this page you must reload widget.js. Most consumers want stop() instead. |
Session continuity
Conversation history is stored on the server. The widget keeps a session_id in the visitor's browser (localStorage) for up to 24 hours — on return visits it fetches the previous conversation from the server using that ID, so history persists across page reloads.
When userHints includes user_id or email, the storage key is scoped per visitor — different users on the same device get separate sessions.
Cross-device resume is not supported: the session_id lives in the local browser only.
When the bot escalates a conversation to a human agent, the chat is marked as ended. The transcript stays visible; a "Start new chat" button appears for the visitor to open a new session.
Greeting is shown once per new session and not repeated on resume.
Clarification: the bot may ask one follow-up question when a request is ambiguous. It appears as part of the normal text reply.
Login / logout in single-page apps
Because start, stop, and setHints are explicit, the widget can survive a full SPA login/logout cycle without reloading widget.js.
Substitute your own brand color in color (any #RGB/#RRGGBB) — or omit it for the default violet gradient. All other options listed in Configuration are supported here too.
setHints() updates a running widget in-place — you do not need to stop and start to change identity.
For server-rendered or multi-page apps, the simplest pattern is to render the embed snippet on every page and pass the right userHints per request. On logout the page navigates and the widget is recreated naturally.
userHints
By default the widget is anonymous. Pass userHints to personalize the session — either at start() time, or later via setHints():
Hints are used for greeting personalization, language selection, and escalation email metadata.
Note: Hints come from the browser and can be modified by anyone. Do not use them for access control, paid-tier gating, or audit logs. Treat them as personalization suggestions only.
Fields
| Field | Notes |
|---|---|
user_id | Stable ID from your system. Primary key for session grouping. Falls back to hint:<email> if absent. |
email | Used in escalation notifications. Malformed values are dropped. |
name | Display name. |
plan_tier | "free", "starter", "growth", "pro", "enterprise". Affects escalation priority. |
audience_tag | Free-form segment label. |
locale | BCP-47 (e.g. "en-US", "ru-RU"). Overrides browser locale for language selection. |
Escalation priority
| Trigger | Other tiers / None | "pro" or "enterprise" |
|---|---|---|
| User requests a human | High | Critical |
| No relevant answer found | Medium | High |
| Answer rejected by quality check | Medium | Medium |