# Web widget

Try the agent on the inbox's **Test** page, the link `vatio push` prints.
To put chat in front of customers on your own website, publish the agent and
create a token that allows your site's origin:

```bash
vatio push
vatio publish
vatio tokens create --env live --label website \
  --origin https://acme.com --origin http://localhost:3000
```

Each publishable token has its own allowed origins, and works only from those
plus Vatio's own pages and the app builders. They govern the whole public API — the widget, the
browser SDK and iOS and Android apps alike. Origins are exact `scheme://host[:port]`
values, with no path or wildcard. An iOS app is `ios-app://` plus its bundle
id — see the [iOS SDK](https://vatio.ai/docs/sdk/ios) — and an Android app is `android-app://` plus
its package name — see the [Android SDK](https://vatio.ai/docs/sdk/android).

Every token also accepts any `https` subdomain of the app builders, preview and
published alike, without listing it: Lovable (`lovable.app`,
`lovableproject.com`), Replit (`replit.dev`, `replit.app`), Bolt (`bolt.host`,
`webcontainer-api.io`), v0 (`vusercontent.net`) and Base44 (`base44.app`). A
token with no origins works only there. Once the app moves to a domain of its
own, list that one.

A page on an origin the token does not accept gets `origin_not_allowed`, and the
browser console names that origin, ready to paste. Change a token's list with `vatio tokens origins PREFIX URL...` or on
the tokens section of **Channels → Web widget** in the inbox, which also lists
the token in the install snippet that page shows.

Copy the returned `vatpub_` token into your page:

```html
<script async src="https://cdn.vatio.ai/v1/widget.js"
        data-workspace="acme"
        data-token="vatpub_REPLACE_ME"></script>
```

Publishable tokens are intended for page source and select one workspace and
environment. They do not authorize deployment or access to the workspace inbox.
Never use a `vat_` developer token in a browser.

## From your app's code

With a bundler, install the widget from npm and mount it yourself. It is the
same widget, with the same options as the `data-*` attributes, in camelCase:

```sh
npm install @vatio-ai/widget
```

```js
import { mountVatioWidget } from "@vatio-ai/widget";

const widget = mountVatioWidget({ workspace: "acme", token: "vatpub_REPLACE_ME" });

widget.identify(jwt); // who is signed in now, or null to sign out
widget.unmount();     // closes the connection and removes the widget
```

In React, mount it in an effect and return `widget.unmount` as its cleanup.
There is one widget per page: a second `mountVatioWidget` does nothing until
the first is unmounted. The widget is open source (MIT), at
[github.com/vatio-ai/widget](https://github.com/vatio-ai/widget).

`vatio env` prints an environment's install snippet with its token; the
**Channels → Web widget** in the inbox edits the widget's look and its tokens'
origins.
`vatio tokens list` lists tokens; `vatio tokens revoke PREFIX` revokes one.
Revocation prevents new chats and conversation lists with that token; existing
chat credentials remain valid until expiry.

## Widget configuration

Visual values resolve in this order: page override, workspace setting, platform
default. Set the shared defaults in **Channels → Web widget** in the inbox, and
use `data-*` attributes for a specific page.
These settings belong
to the workspace, not to a deployment: they apply to every environment as soon
as you save. `widget:` and `allowed_origins:` in an older `vatio.yml` are
ignored, with a warning on push.

The logo, the brand color and `about` belong to the business: they are set on
the [Business](https://vatio.ai/docs/channels/inbox#business) page of the inbox, or with
[`vatio business set`](https://vatio.ai/docs/cli/business), and marked † below. Everything else is
in Channels → Web widget.

| Field | Page attribute | Value / default |
|---|---|---|
| `accent_color` † | `data-accent` | `#RRGGBB` brand color |
| `accent_ink` | `data-accent-ink` | `#RRGGBB`; otherwise automatic contrast |
| `surface`, `ink`, `muted`, `line` | `data-surface`, `data-ink`, `data-muted`, `data-line` | `#RRGGBB` theme colors |
| `scheme` | `data-scheme` | `auto`, `light`, or `dark`; default `auto` |
| `position` | `data-position` | `right` or `left`; default `right` |
| `reply_style` | `data-reply-style` | `stream`: one answer, written out as it arrives. `paced`: short messages, each after a typing indicator, as on WhatsApp and Instagram. Default `stream` |
| `font` | `data-font` | CSS font stack; `inherit` uses the host's font |
| `radius` | `data-radius` | CSS length such as `16px`; default `16px` |
| `title` | `data-title` | Up to 200 characters; defaults to the agent's name |
| `greeting` | `data-greeting` | Up to 200 characters; defaults to localized copy |
| `suggestions` | `data-suggestions` | Up to four prompts, 200 characters each; attribute uses pipe-separated text |
| `about` † | `data-about` | Up to 2,000 characters of visitor-facing copy |
| `locale` | `data-locale` | `en`, `es`, or `pt`; default `en` |
| Logo † | — | PNG, JPEG, WebP, or GIF upload, up to 2 MB |

`about` is displayed to visitors; the business description the agent works
with is set on the [Business](https://vatio.ai/docs/channels/inbox#business) page of the inbox. `locale` sets interface labels; the agent's language
follows the conversation.

For example, `data-suggestions="Products|Track an order"` sets two prompts.

The widget normally waits for page load and idle time; `data-eager="true"`
starts it immediately.

To tell the agent who is signed in, render a visitor token onto the same tag —
see [Sessions and channels](https://vatio.ai/docs/authentication/sessions). To build your own UI
instead of embedding this one, use the [browser SDK](https://vatio.ai/docs/sdk/).

## Visitor feedback

The widget asks how the conversation went when Jev detects a resolved request, visitor confirmation of closure, and no pending question or action. Evaluation runs in the background a few seconds after the agent's last message, using the latest 12 user and assistant messages (up to 4000 characters each), rather than message counts or inactivity; a visitor who writes again in those seconds is not asked. The question is written for that conversation in the agent's voice, and falls back to “How did [agent name] help you?” when it cannot be.

Feedback is offered once per conversation: Good, So-so, or Bad, with an optional comment of up to 2000 characters for So-so and Bad. Visitors can skip it or continue chatting. Ratings appear in the inbox separately from supervisor ratings, and in `visitor_feedback` on the developer chat API.
