Overview
The Website Chat Widget lets you embed a Spinnable worker directly on your website as a floating chat window. Visitors can ask questions, get support, or interact with your worker — all without leaving your site.The widget is configured from your worker’s Details → Website Widget section in the Spinnable dashboard. This guide covers the implementation details for embedding and customizing the widget on your website.
Quick Start
Enable the widget
In your worker’s dashboard, go to Details → Website Widget, create a widget key, and configure your allowed domains.
Add the embed code
Copy the embed snippet from the dashboard and paste it into your website’s HTML, just before the closing Replace
</body> tag:wk_xxxxx with the widget key from your dashboard.Visitor Identification
By default, the widget assigns each browser a random anonymous ID stored inlocalStorage. This means visitors get a fresh identity per device/browser and their sessions are not linked across devices.
To provide a better experience — like linking conversations to your own user accounts and letting visitors see their past sessions — you can identify visitors using SpinnableWidget.init().
- Anonymous (Default)
- Identified Visitor
- Identified + Profile
When no visitor identification is provided, the widget automatically:
- Generates a unique ID per browser and stores it in
localStorage - Sessions are tied to that browser only
- If the visitor clears their browser data, their history is lost
About the init polyfill
You’ll notice the init snippet includes a small “polyfill” block before the widget script:SpinnableWidget.init() can be called before the widget script finishes loading. The widget script loads with defer, so this polyfill safely stores your configuration until the widget is ready to pick it up. You can place SpinnableWidget.init() anywhere on the page — before or after the widget script.
Session Management
The widget supports multiple conversation sessions per visitor:- New visitors see an intro panel with a welcome message and suggested prompts (configured in the dashboard)
- Returning visitors (identified via
visitorId) see a list of their past sessions and can:- Open any previous conversation to continue it
- Start a new conversation with the New Chat button
- The current session is persisted in
localStorageand survives page refreshes
Theming & Customization
Via the Dashboard
The primary way to customize the widget’s appearance is through the Styling tab in Details → Website Widget. You can configure:- Panel title — the header text shown at the top of the widget
- Theme colors — primary, background, foreground, and text colors
- Intro panel — heading, description, and suggested prompt buttons
- Input placeholder — the placeholder text in the message input
- Launcher icon — choose between
chat,help, orsupporticons - Launcher position —
bottom-rightorbottom-left
Via JavaScript (Per-Page Overrides)
For advanced use cases — like matching different themes on different pages — you can override the dashboard config by passing atheme object to SpinnableWidget.init():
JavaScript overrides take priority over dashboard settings. This lets you use the dashboard as a default while customizing specific pages as needed.
All available theme properties
All available theme properties
| Property | Description | Default |
|---|---|---|
primary | Buttons, header, user message bubbles, launcher | Emerald green |
primaryForeground | Text on primary-colored elements | White |
background | Widget panel background | White |
foreground | Main text color | Dark gray |
border | Borders and dividers | Light gray |
muted | Muted UI elements | Slate |
mutedForeground | Secondary text (empty states, descriptions) | Slate |
errorBg | Error state background | Light red |
errorText | Error state text | Dark red |
fontFamily | Font stack | Inter, system-ui, sans-serif |
borderRadius | Panel corner radius | 12px |
borderRadiusSm | Input and button corner radius | 8px |
Allowed Domains & Security
The widget uses your Widget Key and Origin validation to ensure only authorized websites can embed your worker:- Every request from the widget includes the
X-Widget-Keyheader and the browser’sOriginheader - The backend validates both against your configuration
- Wildcard domains are supported (e.g.,
https://*.acme.commatches all subdomains)
Key Regeneration
If you suspect your widget key has been compromised, you can regenerate it from the dashboard:- A new key is issued immediately
- The old key remains valid for 24 hours (grace period) so you have time to update your embed code
- After 24 hours, the old key stops working
Action Modes
When creating a widget key, you choose an action mode that controls what your worker can do when responding to widget visitors:| Mode | Description |
|---|---|
| Guest (recommended) | Read-only interactions — safest for public websites |
| Collaborator | Limited access — can read and contribute but not manage |
| Org Member | Can read and contribute with broader permissions |
| Owner | Full access — use with caution on public sites |
File Uploads
The widget supports file uploads from visitors:- Maximum 3 files per message
- Maximum 5 MB per file
- Drag-and-drop is supported
Troubleshooting
Widget shows a 403 error
Widget shows a 403 error
Your website’s domain is not in the allowed domains list. Go to Details → Website Widget → Allowed Domains and add your domain (e.g.,
https://example.com). Wildcard patterns like https://*.example.com are also supported.Widget shows a 401 error
Widget shows a 401 error
The widget key is invalid or has been revoked. Check your key in the dashboard — if it was regenerated more than 24 hours ago, the old key has expired. Update your embed code with the new key.
Widget doesn't appear on the page
Widget doesn't appear on the page
Verify the following:
- The embed code is placed before the closing
</body>tag - The
keyattribute on<spinnable-widget>matches your dashboard key - The script
srcURL is correct and accessible - Check your browser’s developer console for errors
Visitor sessions are not persisting across devices
Visitor sessions are not persisting across devices
If you’re using the default anonymous mode, sessions are tied to
localStorage — they only exist in that specific browser. For cross-device persistence, implement Visitor Identification with a consistent visitorId from your user system.Theme changes aren't showing
Theme changes aren't showing
A few things to check:
- Dashboard theme changes apply on the next widget load — refresh the page
- JavaScript overrides via
SpinnableWidget.init()take priority over dashboard settings - Ensure color values are valid CSS (hex, HSL, or named colors)