Skip to main content

Widget Integration

Add the ChatterMate chat widget to your website using either direct script integration or iframe embedding, then choose where it sits and how visitors open it.
Widget Integration Options

Integration Methods

Add the following code snippet to your website’s HTML, just before the closing </body> tag:
Replace YOUR_WIDGET_ID with your unique widget identifier from the ChatterMate dashboard.

2. IFrame Integration

Alternatively, embed the chat widget using an iframe:
The iframe method is useful for testing or when you need more control over the widget’s placement and dimensions.

Placement

By default the launcher is a round bubble 20px from the bottom-right corner, and the chat window opens above it. You can change that in two places:
  • In the dashboard — the Widget placement section of your agent’s Customization tab. These are the defaults for every site the agent is embedded on.
  • In the embed snippet — anything you set on the page wins over the dashboard, so one agent can look different on your pricing page than in your docs.
Colours, fonts and the chat design itself are set in the same Customization tab; placement is only about where the widget sits and how it opens.

Ways to present the widget

Floating bubble

displayMode: 'floating' — the default, on the left or right, with a chat window above it.

Sidebar drawer

displayMode: 'sidebar-left' or 'sidebar-right' — a full-height panel sliding in from that edge.

Search bar

displayMode: 'search-bar' — the launcher becomes a search-style bar that opens a centered palette.

No launcher

launcher: false — nothing is drawn until you open the chat from your own button.
The search bar mode needs the Ask Anything or Aurora chat design, because those are the two designs that open as a command palette. The dashboard greys the option out for other designs.

Setting placement on the page

Set window.chattermateConfig before the loader script. No JavaScript calls needed:
ChatterMate.init() takes exactly the same options if you prefer to configure the widget after the script has loaded:

Options

The legacy form position: { bottom, right } still works — right is treated as offset — so existing installations need no changes.
You can also reposition the widget after it has loaded, which is useful when your layout changes:

Mobile

On small screens the chat always opens full-screen, whichever display mode you choose. Your offsets still control where the closed launcher sits, so it can be kept clear of a bottom navigation bar.

Using your own button

Hide the built-in launcher and open the chat from an element of your own. There are three ways, and none of them requires you to write an event handler.
Add the attribute to any element. It works for elements added to the page later, too.
With the launcher hidden there is nowhere to show the unread badge or the greeting nudge. Listen for the unread event if you want to show a count on your own button.

JavaScript API

window.ChatterMate is available as soon as the loader script runs. Calls that arrive before the widget has finished loading are queued and applied once it is ready, so you do not have to wait.

Prefilling a message

open({ message }) puts text in the input without sending it, so the visitor can edit it or just press enter. Good for “Ask about pricing” links next to a plan:

Login and logout in a single-page app

The widget’s identity is fixed when it loads — the token it starts with decides whose conversation it shows. An app that signs a visitor in or out without reloading the page has to say so, or the widget keeps the identity it had when the script first ran: anonymous after a login, the previous user after a logout.
A change of visitor rebuilds the widget in place: the chat closes, the previous conversation is closed on the server too, and the widget reloads as the new person. identify() with the token the widget is already running on does nothing, so it is safe to call on every route change. Handing identify() a fresher token for the same visitor is not a change of identity: the widget takes the new token and keeps the conversation open, so re-authenticating never costs someone the chat they are in the middle of. Two more lifecycle methods:
destroy() removes the launcher, the chat frame, the injected styles, and every listener and timer the loader added, so nothing of ours is left on the page. It does not clear the stored identity — a later reload() comes back as the same visitor, so use logout() if that is what you want.
With token authentication required, logout() leaves the widget without a token and it cannot load. Pair it with hideLauncher(), or call destroy() instead.

Staying signed in on a long-lived page

A token from /generate-token lasts as long as you asked for — an hour by default. The widget renews it on its own well before it lapses, so a tab left open all day keeps the visitor signed in, and a new chat they start hours later still arrives in your inbox as that person, with their custom_data. Renewal keeps the same customer and the same lifetime, and stops if you revoke the token. It cannot run forever: after 30 days your app has to identify the visitor again. That only leaves the case where the widget has no live token to renew — the tab was asleep past the expiry, or the token was revoked. The widget cannot mint one itself (that needs your API key), so give it a way to ask:
tokenProvider is called only when the widget needs a token you alone can issue. The replacement is handed to the running widget, so the visitor keeps the conversation they were in. Without one, the widget falls back to an anonymous visitor and fires identityExpired so you can react yourself.
Return a token for the same person. tokenProvider replaces an identity that ran out; it is not a way to switch visitors — use identify() for that.

Events

authenticated is false when the conversation belongs to an anonymous visitor rather than the person you identified — a signal that the widget is running without a live token from /generate-token.
ready fires only once. If you subscribe after it has already happened — for example from consent-gated or lazily loaded code — your handler is called immediately rather than never.

Event Handling

The widget supports the following events:

Token Management

Scroll Control

Security Features

  • Tokens are encrypted and stored securely
  • Communication uses postMessage for security
  • Automatic token management
  • Domain validation for widget loading

Widget Features

Customer Identification

  • Email collection before chat starts
  • Automatic returning customer detection
  • Previous conversation history loading
  • Context maintenance across sessions

Chat Interface

  • Real-time message updates
  • Typing indicators, shown only while a reply is actually being written
  • Message status tracking
  • File attachment support
  • Markdown formatting support
  • Emoji support

Availability

The line under the agent’s name reflects who is answering.
  • While the AI is answering it reads Online · replies instantly, which holds at any hour
  • When a person has to answer — an agent in human mode, or a chat a teammate has taken over — it follows your organization’s business hours: usually replies in a few minutes while you are open, we’ll reply when we’re back outside them

Styling

The widget uses CSS variables for consistent theming:

Testing Your Integration

Test Project

We provide a sample test project at github.com/chattermate/chattermate.chat/tree/main/chattermate-test:
  1. Clone and setup:
  1. Start test server:
  1. Open http://localhost:3000 and enter your widget ID
The test project demonstrates:
  • Basic widget initialization
  • Token management
  • Style customization
  • Mobile responsiveness
http://localhost:3000/ui-options.html is a gallery of every placement option — one card per scenario, each opening a page with the widget configured that way and buttons wired to the JS API. Each card runs in one of two modes, chosen at the top of the gallery:
  • Stub fakes the widget entirely, so you can check placement, the JS API and the events with no backend running.
  • Real loads your actual widget — fill in your widget ID and API URL first.

Best Practices

  1. Implementation
    • Add script just before closing body tag
    • Enable secure token storage
    • Test on multiple browsers
    • Verify mobile responsiveness
  2. Security
    • Store tokens securely
    • Use HTTPS only
    • Implement proper CSP headers
    • Enable domain restrictions
  3. User Experience
    • Test email collection flow
    • Verify history loading
    • Check offline behavior
    • Test connection handling

Troubleshooting

  • Verify localStorage access
  • Check token storage events
  • Clear stored tokens and retry
  • Verify domain permissions
  • Check CSS variables
  • Verify mobile breakpoints
  • Test iframe dimensions
  • Validate color codes
  • Check whether Hide launcher is on in the Widget placement section — with no launcher, the chat only opens from your own button or ChatterMate.open()
  • If your site has a high-stacking header or modal, raise zIndex
  • Confirm the loader script actually loaded and window.ChatterMate is defined
  • In a single-page app the widget keeps the identity it loaded with — call ChatterMate.identify(token) after login and ChatterMate.logout() after logout (see login and logout in a single-page app)
  • identify() ignores an empty token, so check yours is a real string and not undefined stringified by your auth store
  • Handing identify() a fresher token for the same person keeps their conversation rather than rebuilding — use reload() if you actually want a rebuild
  • It needs the Ask Anything or Aurora chat design, set under Customization → Chat design
  • Verify widget ID
  • Check network connectivity
  • Test WebSocket connection
  • Validate API endpoints

What’s Next?

After integrating the widget:
  1. Test customer identification flow
  2. Verify conversation persistence
  3. Monitor connection stability
  4. Test mobile responsiveness

Human Agents

Next: Learn how to manage human agents