Widget API
Control the bubble from the host page.
Loader
Calls made before the script finishes load are queued and replayed. The widget never bundles React. Methods throw or reject only after boot if the site key is disabled or the network fails.
While loading, a stub implements the same method names so host code can call window.canwechat immediately after the script tag.
open
Signature: open(): void.
Opens the chat panel. Clears the visitor unread count to 0 and emits open (and unread with 0). If a conversation is active, marks messages read on the server.
Params: none. Returns: void.
Example: call after a CTA click so the visitor lands in an open composer.
window.canwechat.open();close
Signature: close(): void.
Closes the chat panel and emits close. The launcher stays visible unless hide() was used.
Params: none. Returns: void.
window.canwechat.close();toggle
Signature: toggle(): void.
Opens the panel if it is closed, or closes it if it is open. Equivalent to calling open() or close() based on isOpen().
Params: none. Returns: void.
window.canwechat.toggle();isOpen
Signature: isOpen(): boolean.
Returns whether the panel is currently open. The pre-boot stub tracks open/close calls so this stays accurate before the runtime finishes loading.
Params: none. Returns: true when the panel is open, otherwise false.
if (window.canwechat.isOpen()) { /* ... */ }hide
Signature: hide(): void.
Hides the launcher and panel without destroying the widget. Use when the host UI needs the bubble out of the way temporarily.
Params: none. Returns: void.
window.canwechat.hide();show
Signature: show(): void.
Shows the launcher again after hide(). Does not force the panel open.
Params: none. Returns: void.
window.canwechat.show();unread
Signature: unread(): number.
Returns the visitor unread count for the active conversation (agent replies received while the panel was closed).
Params: none. Returns: a non-negative integer. The stub returns 0 before boot.
const n = window.canwechat.unread();prefill
Signature: prefill(text: string): void.
Sets composer text without sending, opens the panel, and truncates input to 5000 characters.
Params: text — string to place in the composer. Returns: void.
window.canwechat.prefill("I need help with billing");send
Signature: send(text: string): Promise<void>.
Trims and truncates text to 5000 characters, opens the panel if needed, ensures a visitor session, then posts a visitor message. Empty or whitespace-only text resolves without sending.
Params: text — message body. Returns: a Promise that resolves when the message is acknowledged.
Errors: rejects if the session cannot be created (session_failed) or the send request fails (send_failed), including inactive plans and network failures. On failure the composer is restored with the attempted text.
Example: programmatically start a conversation from a pricing or support CTA.
await window.canwechat.send("I need help with billing");identify
Signature: identify({ id?, name?, email? }): Promise<void>.
Attaches visitor identity on the active session. Same pipeline as data-user-id, data-name, and data-email on the script tag. At least one field is required for the call to be useful; visitors can still chat without identity.
Params: id (optional string), name (optional string), email (optional string). Returns: a Promise that resolves after the session PATCH.
Errors: rejects if the session cannot be created first (session_failed) or the network fails before the identity update completes.
Example: call after your app login so inbox and integrations show a known visitor.
await window.canwechat.identify({ email: "ada@example.com", name: "Ada" });page
Signature: page(url: string): Promise<void>.
Updates the current page URL on the visitor session. Useful for SPA route changes where location.href alone is not enough context for agents.
Params: url — absolute or page URL string to store. Returns: a Promise that resolves after the page update request.
Errors: rejects if the session cannot be created first (session_failed) or the network fails.
Example: call from your router after each client-side navigation.
await window.canwechat.page(location.href);destroy
Signature: destroy(): void.
Tears down the widget: closes the socket, removes the Escape key listener, and removes the host node from the DOM.
Params: none. Returns: void. After destroy, create a fresh script load if you need the widget again.
window.canwechat.destroy();on
Signature: on(event, callback): () => void.
Subscribes to a widget event. event is one of ready, open, close, message, reply, unread, disabled, or *.
Params: event — WidgetEventName string; callback — function receiving the event payload (and event name for *). Returns: an unsubscribe function that removes that callback.
Sticky note: for ready, if the widget is already booted when you subscribe, the callback fires immediately.
Errors: none from on() itself. Callbacks should not throw; wrap host logic if needed.
Example: listen for agent replies or unread changes, then call the returned function to unsubscribe.
const off = window.canwechat.on("message", (msg) => console.log(msg));
off();ready
Trigger: fires once after a successful widget boot. Also invoked immediately when you subscribe with on("ready") after boot (sticky).
Payload: none (callback is called with no meaningful payload).
Sticky: yes — late subscribers still receive an immediate ready callback.
Unsubscribe: call the function returned by on("ready", ...).
window.canwechat.on("ready", () => {
console.log("widget ready");
});open (event)
Trigger: the panel opens via open(), toggle(), prefill(), send(), or the launcher.
Payload: none.
Sticky: no — only future open events after you subscribe.
Unsubscribe: call the function returned by on("open", ...).
window.canwechat.on("open", () => {
console.log("panel opened");
});close (event)
Trigger: the panel closes via close(), toggle(), Escape, or the panel close control.
Payload: none.
Sticky: no.
Unsubscribe: call the function returned by on("close", ...).
window.canwechat.on("close", () => {
console.log("panel closed");
});message
Trigger: a visitor-side send is acknowledged by the server (first message or follow-up).
Payload shape: { id: string; senderType: "visitor" | "agent" | "system"; body: string; createdAt: string }.
Sticky: no.
Unsubscribe: call the function returned by on("message", ...).
window.canwechat.on("message", (msg) => {
console.log("visitor message", msg);
});reply
Trigger: an agent message arrives over the conversation socket.
Payload shape: { id: string; senderType: "visitor" | "agent" | "system"; body: string; createdAt: string } (agent replies use senderType "agent").
Sticky: no. The widget also updates an aria-live region for incoming reply text.
Unsubscribe: call the function returned by on("reply", ...).
window.canwechat.on("reply", (msg) => {
console.log("agent reply", msg);
});unread (event)
Trigger: the unread count changes — typically when an agent reply arrives while the panel is closed, or when open() resets unread to 0.
Payload: a number (the new unread count).
Sticky: no.
Unsubscribe: call the function returned by on("unread", ...).
window.canwechat.on("unread", (count) => {
console.log("unread", count);
});disabled
Trigger: the site key is inactive or the widget config reports enabled: false during boot.
Payload: none. The host node is removed and window.canwechat is replaced with a no-op stub.
Sticky: no — subscribe before or during load (via the stub) if you need to observe this.
Unsubscribe: call the function returned by on("disabled", ...). After disable, further API calls are no-ops.
window.canwechat.on("disabled", () => {
console.log("widget disabled for this site key");
});*
Trigger: every emitted event also notifies wildcard subscribers.
Payload: callback(payload, eventName) — first argument is the event payload (may be undefined), second is the event name string such as "message" or "ready".
Sticky: follows the underlying event (only ready is sticky).
Unsubscribe: call the function returned by on("*", ...).
window.canwechat.on("*", (payload, eventName) => {
console.log(eventName, payload);
});