Skip to main content

Web Quick Start

This walks a React app that uses React Router from zero to an agent that can operate it. For other frameworks, follow steps 1–3, then use the runtime directly.

1. Install​

npm install @appilots/web-sdk
npm install --save-dev @appilots/cli

2. Publish the app map​

The agent needs to know which screens exist, what's on them, and how to reach them. The CLI builds that map and uploads it to your project.

Create .appilotsrc at the project root:

{
"projectId": "proj_...",
"serverUrl": "https://api.appilots.com",
"platform": "web",
"manifestPath": "appilots.manifest.json"
}

platform: "web" makes the analyzer read your React screens and React Router routes. Anything it can't infer — route patterns, field types, which actions are destructive — goes in appilots.manifest.json. See Manifest mode for its format.

{
"version": "1",
"screens": [
{
"name": "VehicleList",
"description": "Lists the fleet. Search, open a vehicle, or delete one.",
"route": "/vehicles",
"actions": [
{ "id": "new-vehicle", "type": "navigation", "label": "New vehicle" },
{
"id": "delete-vehicle",
"type": "custom",
"label": "Delete vehicle",
"effect": "destructive",
"requiresConfirmation": true
}
]
},
{
"name": "VehicleCreate",
"description": "Registers a vehicle.",
"route": "/vehicles/new",
"forms": [
{
"id": "vehicle",
"fields": [
{ "id": "model", "label": "Model", "type": "text", "required": true },
{ "id": "year", "label": "Year", "type": "number", "required": true }
]
}
],
"actions": [{ "id": "save-vehicle", "type": "submit", "label": "Save", "effect": "write" }]
}
],
"navigation": { "initialScreen": "VehicleList" }
}

Then sync, passing the publish key through the environment:

APPILOTS_PUBLISH_KEY=ak_... npx appilots sync

Run the same command in CI on every deploy — see CI integration. The web SDK never reads .appilotsrc, but keep the publish key out of the file anyway: it is a private key, and the environment keeps it out of git.

3. Mount the provider and the chat​

import { AppilotsWebProvider, AppilotsChatFab } from '@appilots/web-sdk/react';
import { useNavigate } from 'react-router-dom';

const ROUTES = [
{ name: 'VehicleList', path: '/vehicles' },
{ name: 'VehicleCreate', path: '/vehicles/new' },
{ name: 'VehicleDetails', path: '/vehicles/:id' },
];

const SCREENS = [
{
name: 'VehicleList',
actions: [{ id: 'delete-vehicle', label: 'Delete vehicle', requiresConfirmation: true }],
},
];

export function Root() {
const navigate = useNavigate();
return (
<AppilotsWebProvider
projectId="proj_..."
apiKey={import.meta.env.VITE_APPILOTS_SDK_KEY} // the SDK key, not the publish key
routes={ROUTES}
screens={SCREENS}
navigate={(path, options) => navigate(path, { replace: options?.replace })}
>
<App />
<AppilotsChatFab locale="en" title="Assistant" />
</AppilotsWebProvider>
);
}
  • routes connects URLs to the screen names in the app map. The names must match the manifest exactly. The SDK uses them to tell the agent where the user is, and to turn the agent's "go to VehicleDetails with id: 42" into /vehicles/42.
  • navigate is your router's navigate function, so agent navigation stays client-side. Without it the SDK falls back to history.pushState plus a popstate event, which most routers observe.
  • screens marks actions that need the user's confirmation before they run. Since web actions run automatically by default, declare every destructive action here (and use data-appilots-action on its button).

AppilotsChatFab adds a floating button that opens the chat. It renders in a portal under document.body, so it needs no CSS import and no layout space. See Chat UI for the docked side view and other options.

4. Verify​

Open the app, click the chat button, and ask for something that crosses screens, for example "Register a 2023 Corolla". The agent should navigate to the form, fill it, and submit.

If it can't find a screen or a control:

  • check that appilots sync reported your screens, and that the screen names in routes match the manifest;
  • check that the control has an accessible name — visible label text, <label for>, or aria-label. An icon-only button without aria-label is invisible to the agent.

Next steps​