Widget JavaScript API
Everything on window.SellioWidget after the embed script loads.
Overview
Install the embed with a framework guide, then call the API from your page. The public methods are open, close, toggle, setVisitor, sendMessage, requestFeedback, hide, show, on, consent, reset, and destroy, plus the isReady property.
sellioSettings
Set this before embed.js runs. The loader reads widgetKey from it.
window.sellioSettings = {
widgetKey: "your-widget-key",
// optional: baseUrl: "https://sellio.chat",
};widgetKeystring
Public workspace key from Settings → Install. Safe to commit.
baseUrlstring?
Override the Sellio origin when loading the embed (advanced).
noncestring?
CSP nonce for the widget's styles on older browsers. Usually not needed: the nonce on the embed script tag is picked up on its own.
deferIdentityboolean?
Consent mode. Nothing is stored in the browser and the visitor is not registered until they open the chat or you call SellioWidget.consent(). The same as a data-defer-identity attribute on the embed script tag. See Consent mode below.
trackQueryParamsstring[]?
Query parameters to keep in the page URLs and referrer the widget reports, besides utm_*. Everything else in the query, and the #fragment, is dropped before it leaves the page, so reset tokens and sign-in codes never reach your inbox.
Consent mode
For sites that ask before tracking. With deferIdentity the launcher still shows, but the widget reads and writes nothing in the browser's storage, loads no chat frame and does not register the visitor. The first of two things ends it: the visitor opens the chat (choosing to talk to you), or your consent manager calls SellioWidget.consent(). Auto-open and the pop-up message wait for consent, and a setVisitor made before consent is applied once storage is allowed.
window.sellioSettings = { widgetKey: "your-widget-key", deferIdentity: true };
// In your consent manager's "accepted" callback:
(window.SellioWidget = window.SellioWidget || []).push(["consent"]);Content Security Policy
The widget renders in a shadow root on its own element under <html>, so the CSS of your page does not reach it and a framework that swaps <body> on navigation (Turbo, htmx, Astro, Swup) leaves it in place. It uses no innerHTML and, in current browsers, no inline <style>, so it works under Trusted Types and a strict style-src. Your policy needs to allow:
script-src https://sellio.chat
connect-src https://sellio.chat
frame-src https://sellio.chatWith a nonce-based script-src, put the nonce on both the settings script and the embed script tag. The chat itself runs in the frame, under our policy, not yours.
On browsers without constructable stylesheets (Safari before 16.4) the styles fall back to a <style> element that carries the nonce of the embed script tag, or sellioSettings.nonce when you set one.
Command queue
The snippet is async. Hosts can queue calls before the API exists:
window.SellioWidget = window.SellioWidget || [];
window.SellioWidget.push(["open"]);
window.SellioWidget.push(["setVisitor", { id: "u_1", email: "ada@example.com" }]);When embed.js finishes, queued [method, …args] entries are replayed on the real API.
Methods
open()void
Open the chat panel. Called before the widget has started, it waits up to 30 seconds. When the chat cannot open (the widget failed to start, is blocked, or is hidden on this page by your visibility rules) the call is dropped and an error event says why, so a "Chat with us" button can fall back to email. On phones the chat is full screen: the page behind stops scrolling and the Back button closes the chat.
close()void
Close the chat panel.
toggle()void
Toggle open / closed.
setVisitor(data)void
Attach userId (or id), name, email, phone, and optional userHash. Queued until the iframe is ready. A userId different from the last one on this browser is another person: the widget resets first, so they never see the previous user's conversations.
sendMessage(message)void
Send a visitor message as if they typed it. Takes a non-empty string, trimmed and cut at 4,000 characters; anything else is ignored with a console warning.
requestFeedback()void
Ask the visitor to rate the open conversation: the feedback sheet slides over the thread. Does nothing until there is a conversation.
hide()void
Hide the launcher, any pop-up and the chat without removing the widget. An open chat is closed first, the chat stays loaded and keeps counting unread replies, and open() while hidden reports OPEN_FAILED with reason HIDDEN.
show()void
Bring the widget back after hide().
isReadyboolean
True once the launcher is on the page, the same moment the ready event fires.
on(event, callback)() => void
Subscribe to widget events. Returns an unsubscribe function; destroy() removes any subscription still attached.
consent()void
Consent mode only: the visitor accepted, so the widget may use storage and register them now rather than on the first open. Does nothing otherwise.
reset()void
Call on sign out. Forgets this browser's visitor (stored id, token and anonymous id), ends the chat session and starts again as a new anonymous visitor, so the next person on a shared computer does not see the previous user's conversations.
destroy(options?)void
Tear down the launcher, iframe, window listeners, the history patch, timers and your on() subscriptions, and give back the page title and scroll. An open chat is closed first, so you still receive close. Safe to re-embed afterwards. The visitor is kept unless you pass { forgetVisitor: true }.
Events
on listens for sellio:<event> CustomEvents on window. Detail is passed to your callback.
readyevent
Embed finished booting: the launcher is on the page. A subscriber added later still receives it once.
openevent
Chat panel opened.
closeevent
Chat panel closed.
newMessageevent
A new message arrived in the widget.
unreadChangeevent
Unread count changed, detail { count }. Fires only on a real change, including the reset to 0 when the chat opens, and always matches the launcher badge.
errorevent
Something the page asked for cannot happen, detail { code, reason?, status?, message? }. Codes below.
INIT_FAILEDcode
The widget could not start: its configuration did not load after two retries with a 10 second timeout each, or the answer was an error. status is set when there was an HTTP answer, and reason when the server refused and said why: ORIGIN_NOT_ALLOWED (this domain is not in the widget's allowed domains, see Settings > Install), WIDGET_DISABLED, INVALID_WIDGET (no widget has this key) or RATE_LIMITED. reason is CSP when your page's Content-Security-Policy blocks the widget; the console names the directive and the origin to allow. The browser console says the same in plain words.
BLOCKEDcode
The widget is switched off for this visitor (for example by country rules).
HIDDEN_BY_RULEScode
open() on a page where your visibility rules hide the widget. The call is dropped, not replayed on a later page.
OPEN_FAILEDcode
open() could not be honoured. reason is INIT_FAILED, BLOCKED, HIDDEN (you called hide()), CSP (your Content-Security-Policy blocks the chat frame), TIMEOUT (still starting after 30 seconds), RENDER_FAILED, or FRAME_TIMEOUT (the chat frame did not load within 12 seconds; the panel then says so and offers Retry, and the event fires once per attempt).
Examples
const off = SellioWidget.on("unreadChange", (detail) => {
console.log("unread", detail);
});
SellioWidget.open();
// Fall back to email when the chat cannot open on this page.
SellioWidget.on("error", (detail) => {
if (detail.code === "OPEN_FAILED" || detail.code === "HIDDEN_BY_RULES") {
window.location.href = "mailto:support@example.com";
}
});
// On sign in: identify the user (a different user resets on its own).
SellioWidget.setVisitor({ userId: "u_1", email: "ada@example.com" });
// On sign out: forget the visitor and start a fresh anonymous chat.
SellioWidget.reset();
// On route teardown (the visitor is kept):
off();
SellioWidget.destroy();Updated . Something wrong or missing? Tell us.