---
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/ja/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