The chat UI runs inside an iframe served by OneBear — it cannot be broken by your site's CSS, and your site's JavaScript cannot read the conversation.
Only the small loader.js runs on your page: it draws the launcher bubble, applies your theme colour, and opens/closes the iframe.
Messages flow through the exact same pipeline as every other channel. Room lifecycle (New → InProgress → Resolved), AI, auto-reply, tags, and follow-ups all work with no extra configuration.
Visitors can be anonymous (default) or identified (you prove who they are with an HMAC — see §6).
Identified mode — reveal / rotate the identity secret (§6).
AI reply name and AI reply avatar — the name and photo visitors see on replies written by the AI. Leave both blank and AI replies stay unnamed. Replies written by a human always carry that agent's own name and photo (§4).
Pre-chat form fields — set Name and Email to Required / Optional / Hidden, and add up to 8 of your own custom fields, in the order they should be asked, each optionally mandatory.
Custom fields your page may send — pick which fields your site is allowed to push values into. Empty by default (§10).
Copy the snippet from the console rather than from this document — the console fills in the correct host for your environment.
The publicKey is not a secret. It is visible in your page source by design, which is why the allowed-origins list (§5) is what actually protects the widget.
Loading is async; the script never blocks your page render.
Common installs: paste into your site footer template (WordPress footer, Shopify theme.liquid, Next.js _document/root layout, Google Tag Manager custom HTML tag).
Delivery status on their own messages (sending / sent / failed), with a retry affordance when a send fails.
A typing indicator while an agent is composing — and agents see one while the visitor types.
An unread badge on the launcher, plus a notification chime, when a reply arrives while the panel is closed (mutable — see §7).
An out-of-hours banner when the shop is closed per its business hours (Settings → Shop info), showing your away message and asking for an email so a reply can reach them.
The pre-chat form, if enabled (§2), before the first message. Returning and identified visitors skip it.
Scrollable product cards (carousel) when the AI or an automation rule sends them; tapping a card action sends that choice as the visitor's own message.
Reply-to (quote). The visitor can quote any message in the thread; the quote block is rendered above their message, and tapping a quote scrolls back to the original when it is still loaded.
Older history on scroll-up — the panel opens on the most recent 50 messages and loads the next 50 each time the visitor scrolls to the top (§8).
An inline satisfaction rating when the conversation is resolved and CSAT is enabled (Settings → Satisfaction). The visitor rates it inside the panel — no link out to a separate page.
Video and file playback for anything an agent sends: video plays in the panel, other files download.
Their own messages in every panel they have open — a second tab, or phone + desktop for an identified visitor, receives the same message they just sent elsewhere.
Full-screen on phones. On a phone-sized viewport the panel opens edge-to-edge instead of as a floating card, tracks the on-screen keyboard, and cannot be pinch-zoomed out of shape. On desktop it stays a 380×560 card above the launcher.
Only messages that actually reached them. An agent message that failed to send is excluded from widget history, so it can never resurface on the visitor's next visit after the agent already retyped it.
The gate is the file extension, not the content type the browser reports — the same .csv arrives as text/csv, application/vnd.ms-excel or nothing at all depending on the visitor's OS. Anything that the media endpoint could serve as active content (.html, .htm, .svg, .xhtml) and every script/executable extension is rejected.
Blank list = any site may embed the widget. Fine while testing; tighten it before going live.
Entries must be full origins — scheme included, no path:✅ https://shop.example.com
❌ example.com (no scheme)
❌ https://example.com/contact (path)
No wildcards. https://*.example.com does not work — list each subdomain you actually use.
A trailing slash is tolerated (https://example.com/ matches), and matching is case-insensitive.
http://localhost:3000 and http://127.0.0.1:5173 are ordinary origins — add them explicitly if you test locally.
The secret is not the publicKey. It must never reach the browser.
Rotate secret immediately revokes the old value. Any page still sending a hash computed with the old secret will fail to start a session — deploy the new secret first, then rotate, or accept a brief outage.
Revealing and rotating both require the SettingsChannelsManage permission.
Conversation history follows the user, not the browser — the same person sees their history on a new device or after clearing cookies.
The pre-chat form is skipped (OneBear already has the name and email).
Agents see the real name, email and phone on the customer record instead of an anonymous visitor.
With avatarUrl set, agents see the user's own profile photo on the conversation instead of initials.
The pre-chat form asks for name + email (each Required / Optional / Hidden) plus up to 8 of your own custom fields (§2). It cannot collect a phone number into the customer's Phone field — a phone typed into a custom field stays a custom field, which list filters, duplicate detection and search do not read as a phone number. Use identify for that (§6).
The panel layout is not customisable beyond the theme colour.
Attachments: 25 MB per file, one file at a time, extensions limited to the allowlist in §4.
Messages have a maximum length enforced by the server; very long pastes are rejected rather than truncated.
Quick-reply buttons do not work on the widget. If an auto-reply rule or the AI attaches them, the widget renders nothing for them (carousel cards do render).
There is no client-side JavaScript event API — you cannot subscribe to "message received" or "conversation started" on your page. open(), close() and reset() are the only hooks (§7).
publicKey is public. It is meant to be readable in your page source. It identifies the widget; it grants nothing beyond starting a visitor session.
The identity secret is a credential. Server-side only, in an environment variable or secret manager. Never in client code, never in a repo.
Allowed domains are a guardrail, not authentication (§5). Combine with identified mode when identity matters.
The panel is sandboxed in an iframe on OneBear's origin — your site's scripts cannot read the conversation, and vice versa.
Uploads are type- and size-restricted (§4) and served back through an authenticated media endpoint, not as public URLs.
Rotating the identity secret is immediate. Deploy the new secret to your servers first if you want zero downtime.
Every widget session is scoped to one company and one channel — a session token issued for widget A can never read widget B's conversations.
No floating launcher. You provide the entry point (a menu item, a tab, a button) and call present(); use unreadCount for a badge.
Full-screen only, with the platform's back gesture / edge swipe to leave the chat.
Attachments work on Android and on the web; on iOS they are not yet available in the SDK.
No push notifications from the SDK — a reply that arrives while the app is closed is shown the next time the chat opens.
Links sent by an agent open in Custom Tabs (Android) / SFSafariViewController (iOS); help-center articles and embedded videos render inside the chat.