Frontend API (JavaScript)
Control the Widget and wire navigation + identity.
Get a Widget instance
import { createWidget, getWidget } from 'https://cdn.chatbyte.ai/spark.min.js';
const widget = await createWidget('your-agent-id');
const existing = getWidget('your-agent-id');Widget controls
widget.open();
widget.close();
widget.toggle();Contextual notifications
widget.showNotification({
id: 'pricing-page',
text: 'Ask us about this page.',
oncePerSession: true,
});
widget.hideNotification('pricing-page');
// Temporarily prevent launcher notifications from overlapping a host UI.
widget.setNotificationsSuppressed(true);
widget.setNotificationsSuppressed(false);Saved automatic prompts are configured in Chatbyte settings. Use showNotification for page-specific runtime context.
Navigation handling
The Widget calls your handler for links to pages on your own website and for link actions. Links in replies that point to other websites, email addresses or phone numbers open in a new tab without calling it.
This example keeps Widget-requested navigation within your website. Allow any other destinations explicitly in your application's navigation policy.
widget.setNavigationHandler((url) => {
const destination = new URL(url, window.location.origin);
if (destination.origin === window.location.origin) {
router.push(destination.pathname + destination.search + destination.hash);
}
});WebMCP (experimental)
Once WebMCP is enabled, Spark discovers eligible tools from the customer page and makes them available to Luna during a Widget reply. This experimental integration targets the current WebMCP draft: document.modelContext.getTools() and executeTool(). Browser support is still evolving; if either method is absent or discovery fails, the Widget continues with normal chat and the existing navigation handler.
Configure WebMCP under your agent's Widget → Settings and save. It is off until you enable it. Under Advanced: restrict tools, you can allow only selected tool names. Turning on that restriction with an empty list allows no tools.
The saved channel settings are authoritative. Spark reads them when it initializes, and the backend checks them for each reply and immediately before issuing an action. Disabling a channel or removing a tool prevents new calls from already open widgets. Actions already issued cannot be undone by changing this setting. Refresh the page after enabling the feature or expanding its allowlist so Spark can discover the newly available tools.
Register tools in the same document that loads Spark. No additional Widget configuration is required:
const context = document.modelContext;
const registration = new AbortController();
if (context?.registerTool && context.getTools && context.executeTool) {
await context.registerTool(
{
name: 'open_settings',
description: 'Open the profile or notification settings screen.',
inputSchema: {
type: 'object',
properties: {
section: { type: 'string', enum: ['profile', 'notifications'] },
},
required: ['section'],
additionalProperties: false,
},
execute: async (input, { signal }) => {
signal.throwIfAborted();
if (!['profile', 'notifications'].includes(input.section)) {
throw new Error('Unknown settings section');
}
await router.push(`/settings/${input.section}`);
return { opened: input.section };
},
},
{ signal: registration.signal },
);
}
const widget = await createWidget('your-agent-id');
// Keep the usual navigation integration for links and unsupported browsers.
widget.setNavigationHandler((url) => router.push(url));
// On application teardown:
// registration.abort();
// widget.destroy();To opt out on an individual website, disable WebMCP discovery and execution when creating the Widget:
const widget = await createWidget('your-agent-id', { webMcp: false });Omitting webMcp follows the saved channel settings. The embed accepts only the false opt-out; tool allowlists belong in Widget → Settings. The backend enforces that channel policy for Luna's calls. Set the opt-out at initialization; changing it requires destroying and recreating the Widget.
The embed option is a convenience control, not authorization. Register only the tools you want to expose, and enforce the visitor's permissions in the tool implementation and any server endpoints it calls. Neither a client-side setting nor an allowed tool name can establish that an action is authorized.
This MVP supports reading context, navigation and reversible form preparation. The customer owns argument validation, permissions and the actual implementation. Spark excludes tools marked consequentialHint or debugging, but annotations cannot prove what an implementation does. Saving, submitting, payments and other consequential operations are outside this MVP; use the channel allowlist when the page exposes additional actions.
The catalogue is refreshed for each message and after every action, then rechecked before execution. After SPA navigation, Luna can use the new page's tools in the same reply. Have your tools resolve after their navigation and tool registration are complete. Stale calls are rejected rather than applied to changed tools; full page reloads end the active turn.
Spark accepts tools registered by its own window and origin. It selects up to 12 usable tools within a 32 KiB catalogue, skips unsupported or oversized schemas, and shortens long descriptions. Schemas must be self-contained. An unsupported tool does not hide the others; use the channel allowlist when you need to select particular tools on a large page. Schemas guide Luna's arguments; Chatbyte checks JSON shape and size without compiling customer schema rules on its backend. Validate inputs and permissions in your tool implementation.
A reply may attempt up to three calls, one at a time, including repeated calls to the same tool with different arguments. Duplicate execution IDs are not run again. Each call has a 20-second limit covering setup, execution and the result. Supported embeds wait up to one second for discovery; embeds without the browser-tool capability skip it immediately. Disconnects, cancellation and uncertain results are not retried automatically, and aborting cannot undo an action that already happened.
Tool descriptions, argument schemas and results are sent to Chatbyte for the active reply; JavaScript functions stay on the website. Provide a verified Widget identity through the normal identify flow. The deprecated contact-ID-only fallback cannot use browser tools.
Identity methods
widget.identify({ token });
widget.onRequestToken(async () => {
const response = await fetch('/api/widget-token');
const { token } = await response.json();
return token;
});For JWT requirements, see JWT & Identity.