Guides
Install and configure the Web SDK
Add the chat to your website with the versioned Web SDK, link signed-in customers through your own backend, and listen to typed events.
On this page
Put Busymate AI on your website with the official Web SDK distribution 0.1.0: a typed package, @busymate/ai-web, that mounts the chat, recognizes customers who are signed in to your product with a token your server signs, and reports every step as an event. Source, the configuration reference and two runnable examples live in the public repository, released as 0.1.0. The SDK pins the page side of the wire to contract v1 (bridge busymate-ai-v1), so updates to the hosted chat never change what your page sends or accepts. The release manifest pins the contract hashes.
The Web SDK is the recommended way to add the chat to a site you build. The one-line embed script keeps working; section 6 shows how to move.
1. Install the pinned version
- Install the packed tarball attached to the 0.1.0 release:
npm install https://github.com/serebano/busymate-ai-sdk-web/releases/download/0.1.0/busymate-ai-web-0.1.0.tgz. The package is not on the npm registry. - Without a bundler, download
busymate-ai-web-0.1.0.iife.jsfrom the same release, serve it from your own origin and pin it withintegrity. It defineswindow.BusymateAIWeb. - The package has no runtime dependencies, ships ESM, CommonJS and TypeScript types, and is safe to import during server rendering: nothing touches the page until
mount()runs in a browser.
Read the versioned installation instructions before wiring callbacks.
2. Mount the chat
import { createBusymateChat, mintFromEndpoint } from "@busymate/ai-web";
const chat = createBusymateChat({
assistant: "your-assistant",
origin: "https://your-assistant.busymate.ai",
mode: "launcher", // "launcher" | "panel" | "inline"
// YOUR authenticated endpoint: { token, nonce } for a signed-in customer, 401 for a guest.
getIdentity: mintFromEndpoint("https://YOUR-PRODUCT-DOMAIN/api/bmai/identity"),
});
chat.onLinkStatus(({ state, reason }) => console.debug("account link", state, reason));
chat.mount();
// Wire YOUR auth events, not your router.
auth.onSignIn(() => chat.identityChanged());
auth.onSwitchAccount(() => chat.switchAccount());
auth.onSignOut(() => chat.logout());| Setting | Purpose |
|---|---|
assistant | Required assistant slug from Console › Integration. |
origin | The serving origin your embed script uses: https://<assistant>.busymate.ai or your verified custom domain. |
mode | launcher (floating button and panel), panel (no button; open it from your UI) or inline (fills container). |
getIdentity | Your provider: a fresh { token, nonce } from your backend, or null for a guest. |
account | Optional: your current account id, read in memory only, to catch a switch you forgot to report. |
locale, theme | First-paint language and theme; later setLocale() and setTheme(). |
onSignInRequest, onNavigate | Optional: handle in-chat sign-in and same-site links in your own router. |
Add your page's exact origin to Console › Integration › allowed origins. The chat refuses to load anywhere else, and the SDK says so (origin_not_allowed) instead of showing an empty panel. See the complete configuration reference.
3. Link signed-in customers
Your backend mints a one-time launch token; the page never holds a key. Build one authenticated endpoint that reads { nonce, returnTo }, signs an ES256 JWT with your workspace claim, sub, the echoed nonce, a unique jti and an expiry within 120 seconds, and answers { token, nonce }. Copy a reference implementation from backend signing. mintFromEndpoint calls it with your cookies, refuses redirects and treats 401 as signed out.
Then wire your own auth events, not your router:
| Your product | Call |
|---|---|
| Sign-in or token rotation | chat.identityChanged(): the same conversation continues, now identified. |
| Account switch | chat.switchAccount(): the previous person's chat is withdrawn first. |
| Sign-out | chat.logout(): the chat drops the identity and clears the transcript. |
| A token you already hold | chat.identify({ token, nonce }) or chat.setUser(...). |
When a guest taps Sign in inside the chat, the SDK sends them to your login page with return_to set to the current page and picks the token up when they return. Pass onSignInRequest to keep them on the page with your own login modal. See in-chat sign-in and the identity guide.
4. Listen to events
chat.on(name, listener) is typed. ready reports the visitor kind, open and close report the source, message mirrors every chat message for logging, navigate, signInRequest and sessionEnded report what the chat asked, and error names a refused origin or a silent frame.
chat.onLinkStatus(listener) reports the account link as { state, reason, source }. state is unlinked, linking, linked or failed. reason is a stable code such as identified, not_signed_in, mint_failed, nonce_mismatch, not_verified or origin_not_allowed. New codes can be added in later releases, so always keep a default branch. See events.
5. Content Security Policy and the frame
Add the chat origin to frame-src and connect-src, and your mint endpoint's origin to connect-src when it differs. cspHeader({ origin }) prints the line for you. The SDK loads no remote script. It injects one style element; pass your policy's nonce. Leave the frame's sandbox and allow="tools; microphone; autoplay" as the SDK sets them, and do not block microphone for the chat origin in Permissions-Policy if you offer voice. Every message is pinned to the frame and its exact origin, never *. See CSP and iframe guidance.
6. Move from the embed script
Existing embed snippets keep working, and nothing is switched off. To move a page, remove the embed script tag and create the chat with the same assistant and the script's origin. Move your getIdentity into the option, then replace identityChanged() and signedOut() with chat.identityChanged() and chat.logout(). The SDK uses the same frame and the same visitor storage, so returning visitors keep their conversations. Never run both on one page. Page tools, the floating window and push layout are not in 0.1.0 yet: keep the script on pages that use them. See the migration table and the widget page API.
Troubleshoot linking
Start from the link status your page logs:
not_signed_in: your provider returnednull. Check that your session reached the mint endpoint.mint_failedornonce_mismatch: your endpoint failed or did not echo the nonce. Thedetailfield has the HTTP status.not_verified: the token reached the chat, but the verifier refused it. Open the conversation in the Console and read its account linking timeline. It names the cause, such as wrong issuer or audience, an unknown key id, an expired token or clock skew. Console › People › Identity health shows the same picture across customers.origin_not_allowed: add the page origin to the allowed origins.
Then follow identity troubleshooting.
Verify
- Run the example apps (
npm ci && npm run build, thennode example-app/server.mjs) against a test workspace that allowshttp://localhost:5180; see the example-app instructions. - Open the launcher as a guest:
readyreportsanonymousand link status staysunlinked. - Sign in on your site: link status reaches
linked · identifiedand the chat greets the customer by name. - Switch account and sign out: the previous transcript disappears each time.
- Load the page on an origin that is not allowed: the SDK reports
origin_not_allowed.
Questions
Which version should I install?
Web SDK distribution 0.1.0, the tarball or the script file attached to the release. It speaks wire contract v1, bridge
busymate-ai-v1.Do I have to replace the embed script?
No. Existing snippets keep working. The SDK is the recommended path for new integrations and for pages that need typed events or link status.
Why does the link status say not_verified?
The chat received a token but refused it. The account linking timeline on the conversation in the Console names the exact reason.