CanWeChat
Docs

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.

code
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.

code
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.

code
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.

code
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.

code
window.canwechat.hide();

show

Signature: show(): void.

Shows the launcher again after hide(). Does not force the panel open.

Params: none. Returns: void.

code
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.

code
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.

code
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.

code
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.

code
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.

code
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.

code
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.

code
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", ...).

code
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", ...).

code
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", ...).

code
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", ...).

code
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", ...).

code
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", ...).

code
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.

code
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("*", ...).

code
window.canwechat.on("*", (payload, eventName) => {
  console.log(eventName, payload);
});