Widget API Reference
The Appilot Widget exposes a JavaScript API for programmatic control.
bootAppilotWidget() from the appilot package is the integration API: it
loads the bundle and keeps it authenticated. window.Appilot is the runtime
API the loaded bundle exposes for panel, view, theme and identity control. This
page documents both, and everything on it exists today.
Initialization
bootAppilotWidget(options)
Load the widget bundle and keep it authenticated for the life of the page. Idempotent while the widget is healthy: calls made while it is booting or ready are ignored. After a failed boot the next call retries from scratch.
import { bootAppilotWidget } from 'appilot';
bootAppilotWidget({
widgetScriptUrl: 'https://cdn.appilot.space/widget/v1/appilot.esm.js',
widgetKey: 'wk_live_a1b2c3d4...',
tokenEndpoint: '/api/widget/token',
theme: 'dark',
});
Options (AppilotWidgetBootOptions):
| Field | Type | Required | Description |
|---|---|---|---|
widgetScriptUrl | string | Yes | Widget bundle URL. When absent, the assistant is disabled. |
widgetKey | string | No | Publishable widget key. Optional on a registered domain; required for localhost/dev and server-to-server. |
appilotApiUrl | string | No | Appilot backend base URL. Omit it and the widget bundle uses the host it was built for, which for the CDN build is the Appilot cloud. |
tokenEndpoint | string | No | Identity relay on your own backend that mints an identified widget token (default /api/widget/token). |
tokenBody | Record<string, unknown> | No | JSON body sent to the relay (omitted = relay default). |
getBearer | () => string | null | undefined | No | Supplies the logged-in user's session bearer for the relay call, so the relay federates that user. Return null when there is no session. |
position | 'bottom-right' | 'bottom-left' | No | Button position. |
theme | string | No | Color theme (light, dark, auto, host). Omitted, the bundle's own default (auto) applies. See Theming & dark mode. |
language | string | No | UI language (en, es, de). Omitted, the bundle detects it from <html lang>. |
brandName | string | No | Header brand text and the name signing assistant turns (data-brand-name). Defaults to your organization name. See Brand name. |
surfaceLabel | string | No | How the app names its assistant in console diagnostics. |
timeoutMs | number | No | Maximum time for token relay + bundle readiness (default 10000). |
autoOpen, collapsed, zIndex, piiMasking, userAuth, docsBaseUrl, accent, accentDark, width, height, layout, container | see Configuration | No | The same options as the data-* attributes, in camelCase. Each is stamped on the loader tag only when you pass it. |
Returns: Promise<void>
getWidgetAvailability() / subscribeWidgetAvailability(listener)
Observe boot state so your page can render an honest "assistant unavailable" fallback. getWidgetAvailability() returns the current state ('unknown' | 'booting' | 'ready' | 'unavailable'); subscribeWidgetAvailability(listener) calls listener on every change and returns an unsubscribe function. They pair directly with React's useSyncExternalStore(subscribeWidgetAvailability, getWidgetAvailability).
import { getWidgetAvailability, subscribeWidgetAvailability } from 'appilot';
const stop = subscribeWidgetAvailability((state) => {
console.log('assistant is now', state);
});
// call stop() to unsubscribe
What the loaded widget exposes
Once the bundle has loaded, the whole runtime surface is on window.Appilot.
Everything in this table exists today.
| Method | Signature | What it does |
|---|---|---|
initAppilot | (config) => void | Mount the widget with an explicit configuration. Calling it again replaces the current instance. |
destroyAppilot | () => void | Unmount the widget, drop its listeners, and remove the presence attribute so a co-installed extension restores its own launcher. |
open | ({ prefill? }) => void | Open the panel, optionally with text waiting in the composer. |
close | () => void | Close the panel. |
setView | (view) => void | Declare the current view. See View sync. |
getView | () => object | The last detected view, its id and the method that detected it. |
setTheme | ('light' | 'dark' | 'auto' | 'host') => void | Change the theme policy without remounting, so the open conversation survives. |
setLanguage | ('en' | 'es' | 'de') => void | Change the panel language at runtime, the same way. |
setUserToken | (token | null) => void | Hand the live instance a fresh federated token. bootAppilotWidget calls this on its own refresh; call it yourself when your app authenticates after the widget booted. null clears the identity. |
on | (event, callback) => () => void | Subscribe to a lifecycle event. Returns an unsubscribe function. |
There is no toggle, isOpen, sendMessage, setContext or updateAppilot.
open() and close() cover the panel, and nothing sends a message on the
user's behalf by design: open({ prefill }) puts text in the composer for the
user to review and send.
Appilot.open(options?)
// Just open the panel:
window.Appilot.open();
// Open with a suggested prompt in the composer:
document.querySelector('#generate-scenarios').addEventListener('click', () => {
window.Appilot.open({ prefill: 'Generate three scenarios for this field' });
});
Use it to make "ask the assistant" affordances first-class: a button next to your feature opens the panel with the right prompt ready, instead of telling the user what to type.
Appilot.setTheme(mode) and Appilot.setLanguage(locale)
Both take effect immediately without remounting, so the conversation on screen is preserved. Wire them to your own controls:
myThemeToggle.addEventListener('change', e => {
window.Appilot.setTheme(e.target.checked ? 'dark' : 'light');
});
myLanguageSelect.addEventListener('change', e => {
window.Appilot.setLanguage(e.target.value);
});
See Theming and dark mode for the no-code
data-theme="host" option, which usually replaces the first of these.
Events
Appilot.on(event, callback) returns an unsubscribe function.
const unsubscribe = window.Appilot.on('viewchange', ({ view, method }) => {
console.log('assistant is now on', view, 'detected by', method);
});
unsubscribe();
| Event | Payload | When |
|---|---|---|
ready | { view, viewId } | The widget mounted and the page context resolved. |
viewchange | { view, viewId, method } | The detected view changed. method is sdk, url_pattern, dom_selector, page_title or none. |
contentloaded | { count } | Knowledge for the current view finished loading. count is how many items are in scope. |
open | none | The panel opened, from any cause: the launcher, open(), or autoOpen. |
close | none | The panel closed, from any cause. |
layoutchange | { x, y, width, height } or null | The panel's bounds in viewport CSS pixels changed. |
open and close are notifications, distinct from the commands of the same
name. A page that traps focus inside its own modal subscribes to them to release
the trap while the assistant holds the user's attention.
Keeping host results visible
Subscribe to layoutchange to place your app's result cards beside the panel.
Late subscribers receive the last reported value immediately, and moving,
resizing or changing the layout updates it.
const unsubscribe = window.Appilot.on('layoutchange', bounds => {
positionResultCard(bounds); // Your app chooses a free rectangle.
});
Only the full panel is measured. While its code is loading, keep a compact fallback. Bounds exclude overflowing menus and other overlays. On a small screen, offer an explicit switch between the result and the conversation rather than covering either with an unreadable card. Do not inspect the closed Shadow DOM or assume a fixed width or side.
DOM events
Independently of Appilot.on, the widget dispatches a DOM CustomEvent the
host page can listen to:
| Event | Target | detail | When |
|---|---|---|---|
appilot:turn-complete | document | { conversationId: number | null, tools: string[] } | After each assistant turn completes. tools is the deduped list of tool names invoked during the turn. It never carries message content. |
Use it to refresh your app's data when the assistant writes through your tools:
document.addEventListener('appilot:turn-complete', e => {
if (e.detail.tools.includes('create_record')) refreshRecordList();
});
The page can also dispatch two events the widget listens for:
appilot:viewchange to declare the current view, and
appilot:identity-refresh-requested to ask the boot loader for a fresh user
token. There is no appilot:ready window event; use Appilot.on('ready', ...).
Client actions
registerTool from the appilot package makes one of your own functions
callable by the agent. It has its own page:
Client actions.
Federated authentication
Your backend mints a short-lived Appilot token for the signed-in user and the widget presents it on every turn. The exchange, its error codes and examples in several languages are on The identity relay.
From the page, all you do is point the boot call at your own endpoint:
import { bootAppilotWidget } from 'appilot';
bootAppilotWidget({
widgetScriptUrl: 'https://cdn.appilot.space/widget/v1/appilot.esm.js',
tokenEndpoint: '/api/widget/token',
getBearer: () => getMyAppSessionToken(), // only when your session is a bearer
});
The loader re-relays through that endpoint before the token expires and hands
the fresh token to the live instance, so a long-lived tab stays authenticated.
When your app authenticates after the widget booted, call
window.Appilot.setUserToken(token) yourself.
POST /widget/token uses your server secret and runs on your backend, never in
the browser. The public widget key alone cannot mint a user token.
TypeScript Types
The appilot package includes full TypeScript declarations:
import type { AppilotWidgetBootOptions } from 'appilot';
const options: AppilotWidgetBootOptions = {
widgetScriptUrl: 'https://cdn.appilot.space/widget/v1/appilot.esm.js',
widgetKey: 'wk_live_...',
theme: 'dark',
};