Runtime & Provider
Everything in the web SDK hangs off one object, AppilotsWebRuntime. It owns the connection to the API, the chat session, the action queue, and navigation. AppilotsWebProvider builds one and hands it to React hooks and components. Without React, you create it yourself.
Options
AppilotsWebProvider takes these as props, and new AppilotsWebRuntime(options) takes them as an object.
| Option | Type | Default | Description |
|---|---|---|---|
projectId | string | — (required) | The dashboard project. |
apiKey | string | — | The project's SDK key. Never the publish key. |
apiBaseUrl | string | https://api.appilots.com | API base URL. /api/v1 is appended when missing. |
routes | { name, path }[] | [] | Maps URLs to screen names. path accepts :param segments (/vehicles/:id). Names must match the app map. The most specific pattern wins, so /vehicles/new matches VehicleCreate, not VehicleDetails with id: "new". |
navigate | (path, { replace? }) => void | history.pushState + popstate | Your router's navigate function, so agent navigation stays client-side. |
screens | WebScreenMetadata[] | [] | Per-screen metadata: { name, title?, description?, fields?, actions? }. Its main job is marking actions with requiresConfirmation. See Declared actions. |
autoExecute | boolean | true | Run the agent's actions as they arrive. Confirmations always wait for the user. Set false to make every action wait for approveAction. |
permissions | Partial<AgentPermissions> | fully open | Restricts the agent: canNavigate, canFillForms, canInteractUI, canSubmitForms, allowedScreens, blockedScreens, allowedActions. These run in the browser, so a modified client can bypass them. For rules that must hold, use assessment screens. See Permissions. |
user | { id, name?, identifiers? } | — | The signed-in user. On its own it's only a claim; pair it with getUserToken to make it count. See Sessions & users. |
getUserToken | () => Promise<string | null> | — | Fetches a short-lived end-user token from your backend. When set, it's sent on every request; returning null blocks the request. |
plainLanguage | boolean | dashboard setting | Plain-language replies: short sentences, everyday words, one question at a time. Changes only the wording, not what the agent does. |
timeout | number (ms) | 60000 | How long to wait for a reply, or for a silent stream, before giving up. Agent continuations always get at least 150000. |
root | Element | document | Limit what the agent sees and touches to this subtree. |
chat | { streaming?, errorPrefix?, escalationStrings? } | { streaming: true } | Chat session options. streaming: false uses the non-streaming endpoint. |
appVersion | string | — | Your app's version, reported with each session. |
mcpVersion | string | — | Version of the app map, for correlating replies with a build. |
debug | boolean | false | Log the SDK's internals to the console. |
The agent replies in the browser's language when it's one the agent supports (the first match in navigator.languages).
React: AppilotsWebProvider
import { AppilotsWebProvider } from '@appilots/web-sdk/react';
<AppilotsWebProvider projectId="proj_..." apiKey={sdkKey} routes={ROUTES} navigate={navigate}>
<App />
</AppilotsWebProvider>;
The provider creates a new runtime, and so starts a new conversation, only when projectId, apiKey, apiBaseUrl, or user.id change. routes, navigate, permissions, root, and screens are updated in place, so passing inline arrays and functions is fine.
To own the runtime yourself, build it and pass it in. The provider won't dispose a runtime you inject:
const runtime = useMemo(() => new AppilotsWebRuntime({ projectId, apiKey, routes, screens }), []);
<AppilotsWebProvider runtime={runtime}>…</AppilotsWebProvider>;
useAppilotsRuntime() returns the runtime from anywhere inside the provider.
Hooks for a custom chat
The bundled chat components cover most apps. To build your own surface, use the same hooks they use.
useAppilotsChat(options?)
| Field | Type | Description |
|---|---|---|
messages | ChatMessage[] | The transcript. |
isLoading | boolean | A reply is in progress. |
loadingStatusKey | 'thinking' | 'statusAnalyzing' | 'statusWaitingApp' | 'statusAdjusting' | What the agent is doing, for a status line. |
error | string | null | The last error. Clear it with clearError(). |
pendingActions | AgentAction[] | Actions waiting to run or to be confirmed. |
escalation | EscalationState | null | An open human handoff. While it's set, sendMessage goes to the human operator. |
mission | MissionView | null | The active multi-step task. While it's open, sendMessage only accepts resuming it. |
sendMessage(content) | Promise<void> | Send a user message. |
cancelMessage() | void | Stop the current reply. |
clearMessages() | void | Start a new conversation. |
requestHuman(reason?) | Promise<void> | Hand off to a human operator ('user_requested' by default). |
pauseMission() / resumeMission() / cancelMission() | Promise<void> | Control the active task. |
clearError() | void | Dismiss error. |
options is the same object as the chat runtime option.
useAppilotsActions()
| Field | Type | Description |
|---|---|---|
pendingActions | AgentAction[] | Waiting to run, or waiting for the user (type: 'confirm'). |
executingActions | AgentAction[] | Running now. |
completedActions | AgentAction[] | Finished, successfully or not. |
approveAction(id) | Promise<boolean> | Approve a confirmation (or any action, with autoExecute: false). |
rejectAction(id) | Promise<void> | Reject it. The agent is told the user declined. |
Render a confirmation card for every pending action with type === 'confirm'. Nothing destructive runs until the user answers it.
Without React
AppilotsWebRuntime is a plain class, so it works in Vue, Svelte, Angular, or vanilla JavaScript. You build the chat UI yourself on top of its state machines.
import { AppilotsWebRuntime } from '@appilots/web-sdk';
const runtime = new AppilotsWebRuntime({
projectId: 'proj_...',
apiKey: SDK_KEY,
routes: ROUTES,
navigate: (path) => router.push(path),
});
// Chat state: messages, isLoading, mission, escalation…
const unsubscribe = runtime.chat.subscribeState(() => render(runtime.chat.getState()));
await runtime.chat.sendMessage('Register a 2023 Corolla');
// Action queue: approve or reject confirmations
runtime.actions.subscribeState(() => renderConfirms(runtime.actions.getState().actions));
await runtime.actions.approveAction(actionId);
| Member | Description |
|---|---|
chat | The chat session (sendMessage, cancelMessage, clearMessages, requestHuman, mission controls, subscribeState, getState). |
actions | The action queue (approveAction, rejectAction, subscribeState, getState). |
subscribe(handler) | Listen to SDK events, such as agent:action:complete, navigation:change, and chat:escalation:start. Returns an unsubscribe function. |
configureNavigation({ routes, navigate }) | Update routing after construction, for example once your router exists. |
registerScreen(metadata) | Add or replace one screen's metadata. |
setPermissions(permissions) / setRoot(element) | Update those options at runtime. |
suspend() / resume() | Stop in-flight work (for example, when the host view is hidden) and allow it again. |
dispose() | Tear the runtime down. Call it on logout or unmount. |
On logout or account switch, dispose() the runtime and create a new one, so the next user doesn't inherit the conversation.