Widget JavaScript SDK
Once the chat widget loads, it adds window.SellWhisperWidget to your page. Call its methods to control the widget from your own code, and listen for its events to react to the chat.
Before you start
Add the embed code from your widget first (see the deployment guides). The script loads asynchronously, so wait for window.SellWhisperWidget before calling it:
function whenWidgetReady(callback) {
if (window.SellWhisperWidget) return callback(window.SellWhisperWidget);
const timer = setInterval(() => {
if (window.SellWhisperWidget) {
clearInterval(timer);
callback(window.SellWhisperWidget);
}
}, 100);
}
whenWidgetReady((widget) => widget.open());Integrations written before the rename can keep using window.SolveoWidget. It points to the same methods and logs a one-time deprecation warning.
Methods
open
open(): void
Opens the chat window. Use it to open the widget from your own button or link.
document.querySelector("#help-button").addEventListener("click", () => {
window.SellWhisperWidget.open();
});close
close(): void
Closes the chat window and its conversation history panel. An inline widget always stays open.
window.SellWhisperWidget.close();resetChat
resetChat(): void
Clears the current conversation so the next message starts a new one. The old conversation stays in the visitor's history. Call it when a user logs out.
function onLogout() {
window.SellWhisperWidget.resetChat();
}openConversation
openConversation(conversationId: string): Promise<void>
Opens the widget on an existing conversation and loads its messages, so you can deep-link a visitor back into it. If the conversation cannot be loaded, the widget stays as it was and an error is logged to the console.
const id = new URLSearchParams(location.search).get("conversation");
if (id) await window.SellWhisperWidget.openConversation(id);setOptions
setOptions(options: { appearance?, behavior?, branding?, advanced? }): void
Changes the widget's settings for this page view. Each group takes the same keys as the widget builder (for example behavior.suggested_messages, branding.title, appearance.primary_color). To greet a logged-in visitor personally, pass behavior.initial_messages: a list of messages the widget shows before the conversation starts, in place of your greeting. Keys you leave out keep their current value. Nothing is saved to your widget.
window.SellWhisperWidget.setOptions({
behavior: {
initial_messages: [
"Hi Sara, welcome back!",
"Your order #1042 ships tomorrow. Ask me anything about it.",
],
suggested_messages: ["Track my order", "Start a return"],
},
branding: { title: "Order help" },
});resetOptions
resetOptions(): void
Undoes every setOptions call and restores the settings the widget loaded with.
window.SellWhisperWidget.resetOptions();sendMessage
sendMessage(text: string): void
Sends a message as if the visitor had typed it. Pair it with open() so the visitor sees the reply.
window.SellWhisperWidget.open();
window.SellWhisperWidget.sendMessage("Where is my order?");onAddToCart
onAddToCart(handler: (request) => Promise<{ requestId, ok, message? }>): void
Registers your add-to-cart function for custom storefronts. The widget calls it when the visitor adds a recommended product to the cart; resolve with ok: true once the item is in the cart.
window.SellWhisperWidget.onAddToCart(async (request) => {
await myCart.add({ url: request.url, quantity: request.quantity });
return { requestId: request.requestId, ok: true };
});on
on(event: string, handler: (payload) => void): () => void
Listens for one of the widget events below. Returns a function that stops listening. A handler that throws is logged and never breaks the widget.
const stop = window.SellWhisperWidget.on("assistant-message", (message) => {
console.log("Agent said:", message.content);
});
// Later: stop();off
off(event: string, handler: (payload) => void): void
Stops calling a handler you passed to on() for that event.
function logReply(message) {
console.log(message.content);
}
window.SellWhisperWidget.on("assistant-message", logReply);
window.SellWhisperWidget.off("assistant-message", logReply);Events
Listen with on(). Each handler receives the payload shown under the event name.
user-message
{ content: string, conversationId: string | null, timestamp: string }
The visitor sent a message: typed, tapped or sent with sendMessage(). conversationId is null until the first message starts a conversation.
window.SellWhisperWidget.on("user-message", (message) => {
analytics.track("Chat message sent", { length: message.content.length });
});assistant-message
{ content: string, conversationId: string | null, messageId: string | null, sender: "ai" | "human", senderName: string | null, timestamp: string }
A reply arrived. sender is "ai" for your agent and "human" for a teammate answering a live chat (senderName is their name). Fires once per reply, never for messages reloaded from history.
window.SellWhisperWidget.on("assistant-message", (message) => {
if (message.sender === "human") showBadge(message.senderName + " replied");
});tool-call
{ name: string, arguments: object, conversationId: string | null }
Your agent ran an action while answering, for example shopify.add_to_cart. name is the action's id and arguments are the values the agent gave it. Fires before the reply's assistant-message.
window.SellWhisperWidget.on("tool-call", (call) => {
console.log("Agent is running", call.name, call.arguments);
});tool-result
{ name: string, success: boolean, conversationId: string | null }
The outcome of the action in the matching tool-call. success is false when the action failed or is still waiting for the visitor to confirm or fill in details. The action's raw result stays on our servers.
window.SellWhisperWidget.on("tool-result", (result) => {
if (result.name === "shopify.add_to_cart" && result.success) refreshCartIcon();
});conversation-status
{ status: "open" | "escalated" | "paused" | "ended", conversationId: string | null }
The conversation changed status: open (your agent is answering), escalated (handed to your team), paused (your agent is paused for this conversation, so messages are kept but not answered) or ended (a teammate resolved the live chat). Fires only when the status changes.
window.SellWhisperWidget.on("conversation-status", ({ status }) => {
document.body.dataset.chatStatus = status;
if (status === "escalated") showNotice("A teammate will join shortly.");
});message-feedback
{ messageId: string, feedback: "THUMBS_UP" | "THUMBS_DOWN", conversationId: string | null }
The end user rated one of your agent's answers with thumbs up or down, and it was saved. They can change their mind, so the same answer can fire again with the other rating.
window.SellWhisperWidget.on("message-feedback", ({ feedback }) => {
analytics.track("Chat answer rated", { feedback });
});conversation-deleted
{ conversationId: string }
The end user deleted their conversation from the widget. It is gone from your chat logs too.
window.SellWhisperWidget.on("conversation-deleted", ({ conversationId }) => {
console.log("Conversation deleted", conversationId);
});Every event is also dispatched on window as a sellwhisper: event with the payload in event.detail, so you can listen before the widget has loaded:
window.addEventListener("sellwhisper:conversation-status", (event) => {
console.log(event.detail.status);
});Listeners written before the rename keep working: each event also fires as solveo: (for example solveo:user-message), and window.SolveoWidget.on is the same method.