--- title: "Playground: every way your page and the assistant talk | Busymate AI" description: "The real Busymate AI widget docked on the page and an instrument for every interaction — open and preset it, send prompts from the page, listen to its events, register page tools, call MCP tools, recognise visitors — with the exact code for each." last_updated: "2026-09-17T20:29:25+03:00" --- # Playground: every way your page and the assistant talk | Busymate AI Source: https://busymate.ai/tr/playground Last modified: 2026-09-17T20:29:25+03:00 The real Busymate AI widget docked on the page and an instrument for every interaction — open and preset it, send prompts from the page, listen to its events, register page tools, call MCP tools, recognise visitors — with the exact code for each. The real assistant is docked on this page. Pick an instrument, press its controls, and watch the panel react — then copy the exact code that did it. No account, nothing to install. Reference: https://busymate.ai/docs/guides/widget-page-api ## 1. Open & preset Show, hide and flip the panel; pin its colour scheme and language before the visitor sees it. One tag mounts it; four calls drive it — no iframe of your own to size, no state of your own to keep. ### index.html ```html ``` ### panel.js ```javascript // The loader installs window.BusymateAI. Every call is safe before the frame // has loaded — commands queue and deliver on load. BusymateAI.open(); BusymateAI.close(); BusymateAI.toggle(); BusymateAI.isOpen(); // → true | false ``` ### preset.js ```javascript // Preset the panel from the page: colour scheme + language. // Neither is persisted by the frame — your page owns them while it embeds it. BusymateAI.setTheme("dark"); // "light" | "dark" | "system" BusymateAI.setLocale("de"); // any BCP 47 tag the platform serves BusymateAI.setLocale(null); // unpin — the frame follows the visitor again BusymateAI.open(); ``` Docs: https://busymate.ai/docs/guides/widget-page-api#open-and-preset ## 2. Page → chat Send a prompt from anywhere on the page — a button, a card, a form — or just fill the composer and let the visitor press send. The message takes the same path a typed one does, so nothing is faked and every guard still applies. ### ask.js ```javascript // Open the panel and send a prompt — the same append path a typed message takes. BusymateAI.ask("What can you do on this page?"); ``` ### prefill.js ```javascript // Fill the composer only; the visitor reads, edits and presses send. BusymateAI.ask("Book a table for two on Friday at 19:00", { submit: false }); ``` ### chips.html ```html ``` Docs: https://busymate.ai/docs/guides/widget-page-api#page-to-chat ## 3. Chat → page The panel talks back: it tells the page when a session is live, when the visitor closed it, and when they clicked a link that belongs to your site. A same-site link navigates your page in place — same tab, conversation intact — so the visitor never loses the thread. ### events.js ```javascript // The frame posts busymate.ai.v1.* messages to your page. The loader already // acts on every one of them; your page only listens to OBSERVE. window.addEventListener("message", (event) => { if (event.origin !== "https://busymate.ai") return; const { type, ...data } = event.data ?? {}; if (typeof type !== "string" || !type.startsWith("busymate.ai.v1.")) return; console.log(type, data); // busymate.ai.v1.ready { visitorKind, displayClaims } a session is live // busymate.ai.v1.close — ✕ pressed inside the frame // busymate.ai.v1.navigate { href } a same-origin link was clicked // busymate.ai.v1.open_url { url } any other link (new tab) // busymate.ai.v1.resize_to { w, h } resize_end resize_by { dw, dh } }); ``` ### navigate.js ```javascript // A same-origin link in the chat navigates YOUR page in place (same tab). // SPA routers already listening for popstate resync on their own; this // dedicated event needs no router at all. window.addEventListener("busymate:hostnavigate", (event) => { const { href } = event.detail; myRouter.push(new URL(href).pathname); }); ``` ### open-state.js ```javascript // The panel's open state lives on the launcher's DOM — observe it directly. const layer = document.querySelector("[data-support-chat]"); new MutationObserver(() => { const open = layer.hasAttribute("data-open"); document.body.classList.toggle("assistant-open", open); }).observe(layer, { attributes: true, attributeFilter: ["data-open"] }); ``` Docs: https://busymate.ai/docs/guides/widget-page-api#chat-to-page ## 4. Page tools Declare what this page can do and your mate can do it — through WebMCP where the browser has it, through its own bridge everywhere else. A tool that changes something asks the visitor first, inside the chat, before it runs. ### page-tools.js ```javascript // Declare what THIS page can do. One call, both transports: the browser's // own WebMCP where it exists, the assistant's bridge everywhere else. BusymateAI.registerPageTools([ { name: "set_page_theme", description: "Switch this page between light and dark.", inputSchema: { type: "object", properties: { theme: { type: "string", enum: ["light", "dark"], description: "The scheme to apply" } }, required: ["theme"], additionalProperties: false, }, annotations: { readOnlyHint: false, consequentialHint: true }, execute: async ({ theme }) => { // Flip through your OWN theme mechanism (whatever sets color-scheme / // your CSS variables) so every other themed control on the page agrees // with what this tool just did — never write the DOM attribute alone. const applied = theme === "light" || theme === "dark"; if (applied) myApplyTheme(theme); // Return the RESULTING state, not just "ok": a caller with no applied // flag to check against will report success it never confirmed. return { ok: applied, applied, theme }; }, }, { name: "get_cart", description: "Read what is in the visitor's cart right now.", inputSchema: { type: "object", properties: {}, additionalProperties: false }, annotations: { readOnlyHint: true }, execute: async () => ({ items: cart.items, total: cart.total }), }, ]); ``` ### standard-surface.js ```javascript // The same tools are on the STANDARD surface — any agent, not only ours. const tools = await document.modelContext.getTools(); tools.map((t) => t.name); // → ["set_page_theme", "get_cart", …] ``` Docs: https://busymate.ai/docs/guides/page-tools ## 5. MCP Behind the chat sits a Model Context Protocol server: the tools your mate can call and any other agent can discover, before any sign-in. Connect your own server in the Console and the same conversation reaches your orders, bookings and tickets. ### tools-list.js ```javascript // What the assistant on this page can call: the workspace's MCP server, // discoverable before any sign-in (JSON-RPC over HTTP). const res = await fetch("https://busymate.ai/mcp", { method: "POST", headers: { "content-type": "application/json", accept: "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }), }); const { result } = await res.json(); result.tools.map((t) => t.name); ``` ### ask-for-a-tool.js ```javascript // From the page, a prompt that makes the assistant call one of those tools. BusymateAI.ask("Is the platform up right now? Check the status."); ``` Docs: https://busymate.ai/docs/guides/connect-mcp-server ## 6. Identity A visitor signed in to your product is recognised in the chat automatically; one who is not can sign in without leaving it. Recognised visitors unlock the tools that touch their own data — orders, bookings, invoices — with nothing secret ever crossing the page. ### identity.js ```javascript // Auto-connect: when the visitor is signed in to YOUR product, the chat // knows who they are. Your backend mints a short-lived, one-time proof. // Add getIdentity ONTO the object — never assign a fresh one to // window.BusymateAI: the loader installs every call on THAT object, so // replacing it takes open(), ask() and refreshIdentity() with it. window.BusymateAI = window.BusymateAI || {}; window.BusymateAI.getIdentity = async () => { const r = await fetch("/api/assistant-identity", { method: "POST", credentials: "include" }); return r.status === 401 ? null : r.json(); // { token, nonce } or anonymous }; // Declaring it after the tag already loaded? Hand it over instead: BusymateAI.configure({ getIdentity: window.BusymateAI.getIdentity }); // After YOUR login / logout / account switch: BusymateAI.refreshIdentity(); ``` ### late-identity.js ```javascript // Auth that hydrates AFTER the chat launched anonymously — hand it over late. BusymateAI.identify({ token, nonce }); // remounts as an identified launch ``` ### ready.js ```javascript // The frame tells the page which kind of visitor the session is for. window.addEventListener("message", (event) => { if (event.origin !== "https://busymate.ai" || event.data?.type !== "busymate.ai.v1.ready") return; console.log(event.data.visitorKind, event.data.displayClaims); // "anonymous" | "identified", { name?, … } }); ``` Docs: https://busymate.ai/docs/guides/identified-visitors ## 7. Prompts A handful of prompts that show the range — grounded answers, a tool call, a hand-off, a page it makes for you. Press one; it runs. Each one is a single call from the page, so the same button works on any site that carries the tag. ### prompt.js ```javascript // Every example prompt on this page is one call — the same call your // own "try it" buttons make. BusymateAI.ask("Compare the plans and recommend one for a two-person shop."); ``` Docs: https://busymate.ai/docs/guides/widget-page-api#page-to-chat ## 8. Channels The same assistant answers on your website, in your apps, and on the messaging channels your customers already use. One workspace, one knowledge base, one hand-off inbox — every channel below is a live demo you can open now. ### full-page.js ```javascript // The same assistant as a full page. For an ANONYMOUS visitor that is a // plain link — the workspace address is public. window.open("https://your-workspace-slug.busymate.ai/", "_blank", "noopener,noreferrer"); // To carry an IDENTIFIED visitor across (a different top-level site cannot // read this page's storage), ask the loader to mint the hand-off. Both calls // REJECT unless the getIdentity provider above is configured. const url = await BusymateAI.hostedUrl("https://your-workspace-slug.busymate.ai/"); BusymateAI.openHosted("https://your-workspace-slug.busymate.ai/"); // new tab, same visitor ``` Docs: https://busymate.ai/integrations ## 9. Your site Paste one tag before and everything on this page works on yours. Start from a scan of your own site to see what your mate would already know — no account needed for the preview. ### index.html ```html ``` Docs: https://busymate.ai/docs/getting-started