Embeddable Widget
The embeddable chat widget lets you add an AI assistant to any external website with a single <script> tag. Visitors can chat with your assistant without logging in or leaving the page.
The widget renders inside a Shadow DOM for complete style isolation — it won’t interfere with your website’s CSS, and your CSS won’t affect the widget.
Setup
- Go to the assistant detail page and open the Channels tab
- Click on Browser External and configure the settings (see below)
- Enable the channel
- Set the Access Control to include Public so unauthenticated visitors can use it
- Copy the embed snippet and add it to your website
Embed Code
Add this script tag to any page where you want the widget to appear:
<script src="https://your-teamwebai-domain/static/js/chat-widget.js"
data-assistant-id="123"></script>Script Tag Attributes
| Attribute | Required | Description |
|---|---|---|
data-assistant-id | Yes | The assistant ID |
data-assistant-url | No | The TeamWeb AI server URL (defaults to the script’s origin) |
data-user-token | No | Encrypted identity token for known users (see User Identification) |
Configuration Options
These are set in the channel configuration page in TeamWeb AI:
| Setting | Description |
|---|---|
| Primary Color | Widget accent color (default: #0d6efd) |
| Position | bottom-right or bottom-left (default: bottom-right) |
| Avatar URL | Optional URL for a custom chat bubble avatar |
| Greeting | Initial message shown when the widget opens |
| Widget Title | Title shown at the top of the chat panel (defaults to assistant name) |
| Require Lead Capture | Collect visitor name and email before the first message |
| Allowed Origins | Comma-separated list of origins for CORS (leave empty to allow all) |
How It Works
- A visitor clicks the floating chat bubble on your website
- If lead capture is enabled, they’re asked for their name and email first
- A conversation is created and the greeting message (if configured) is shown
- The visitor types messages and receives responses in real-time (1.5s polling)
- Chat state is stored in
localStorage, so the widget survives page navigation — if the visitor navigates to another page on your site, the chat reopens where they left off - A Contact record is automatically created for each visitor
Cross-Page Persistence
The widget stores its state in the browser’s localStorage:
- Visitor session ID (generated once, persists across pages)
- Current conversation ID
- Open/closed state
- Lead capture completion status
This means a visitor can browse multiple pages on your site while keeping their chat open and intact.
Widget Features
- Responsive — Full-screen on mobile, floating panel on desktop
- Typing indicator — Animated dots shown while the assistant is thinking
- Timeout warning — “This is taking longer than usual…” shown after 60 seconds
- Skeleton loading — Shimmer placeholders while conversation history loads
- End chat — Visitors can end the chat, which triggers the session feedback form (if configured)
- Message feedback — Thumbs up/down on assistant messages (if configured)
- Session feedback — Star rating and comment form when a chat ends (if configured)
- Transcript download — Download the full chat transcript as a text file
Key Differences from Internal Chat
| Feature | Browser Internal | Embeddable Widget |
|---|---|---|
| Authentication | Requires login | Anonymous or encrypted identity |
| User type | Admin / Staff | Public (Contacts) |
| UI | Full admin/staff interface | Floating widget panel |
| Style isolation | Part of TeamWeb AI UI | Shadow DOM (isolated) |
| State persistence | Server sessions | localStorage |
| Voice chat | Yes (with WebRTC) | No |
| Canvas cards | Yes | No |
| Feedback | Yes | Yes |
Rate Limiting
The widget API is protected by rate limiting to prevent abuse:
| Limit | Default | Description |
|---|---|---|
| Messages per session per minute | 10 | Per visitor session |
| Requests per IP per minute | 30 | Per IP address |
| New conversations per IP per hour | 5 | Per IP address |
When a limit is exceeded, the widget receives a 429 response with a Retry-After header. These defaults can be adjusted via environment variables.
CORS
The widget API includes CORS headers on all responses. Configure Allowed Origins in the channel settings to restrict which domains can use the widget. Leave it empty to allow all origins (suitable for development).
For production, set it to your website’s origin (e.g., https://www.example.com).