Event listeners
React to the Bookbag chat widget in the browser and to agent activity server-side. The embedded widget runs in an iframe; use webhooks for reliable server-side events.
View as MarkdownThere are two places you can react to what happens in Bookbag: in the browser around the embedded chat widget, and on your server via webhooks. This page explains which to reach for.
Browser: the embedded widget
The JavaScript embed renders the chat as a launcher button plus a sandboxed iframe. Because the conversation UI runs inside the iframe, your page code does not see individual messages directly — the iframe isolates the chat from your DOM.
What your page can do is observe and control the launcher and frame elements the loader injects into your document. A robust way to react to the widget opening or closing is to watch the injected iframe's visibility:
// The loader injects an <iframe> pointing at /widget/frame.
function onBookbagWidgetReady(cb) {
const tryFind = () => {
const frame = document.querySelector(
'iframe[src*="/widget/frame"]'
);
if (frame) { cb(frame); return true; }
return false;
};
if (tryFind()) return;
const mo = new MutationObserver(() => { if (tryFind()) mo.disconnect(); });
mo.observe(document.body, { childList: true, subtree: true });
}
onBookbagWidgetReady((frame) => {
// The widget shows/hides by toggling display.
const watch = new MutationObserver(() => {
const open = frame.style.display !== "none";
window.dataLayer?.push({ event: open ? "bookbag_open" : "bookbag_close" });
});
watch.observe(frame, { attributes: true, attributeFilter: ["style"] });
});The embedded widget is intentionally minimal: it does not expose conversation contents to the host page, which keeps customer chats isolated from your site's scripts. For reliable, server-side awareness of conversations and leads, use webhooks (below).
Server: webhooks are the source of truth
For anything you need to act on reliably — a lead was captured, a chat was escalated, the agent replied — use webhooks. They are delivered server-to-server, signed, and independent of whether the browser tab is still open.
| You want to know when... | Listen for |
|---|---|
| A visitor leaves their email/phone | lead.created webhook |
| A chat is handed to a human | conversation.escalated webhook |
| The agent replies | conversation.replied webhook |
| An action/tool runs | action.run webhook |
| An outbound campaign goes out | campaign.sent webhook |
Building your own UI?
If you are not using the embed at all but rendering chat yourself, you have full control: call API v2 chat, parse the streaming frames, and emit whatever client-side events you like. The finish frame gives you the conversationId, messageId, and credit usage for each turn.