Embed a widget on your site
You can put the product on your own website with a <script> tag. There are two
widgets, and which one you want depends on whether visitors should have a
conversation or run one specific thing.
| Chat widget | Workflow widget | |
|---|---|---|
| What a visitor gets | A conversation with an assistant | One workflow, with its inputs |
| Interactive forms | Yes | No — it displays results only |
| Script | chat-widget.js |
workflow-widget.js |
Both are self-contained: no framework on your page, no stylesheet to include, and nothing to build.
Add the chat widget
Section titled “Add the chat widget”<script src="https://app.example.com/chat-widget.js"></script><script> sapajaChat('init', { templateId: 'your-template-id', token: 'your-embed-token', });</script>You get the template id and its token from the workspace that owns the chat template. The token is what authorises the widget, and it is tied to a list of sites that may use it — a token used from a domain that is not on that list is refused, so a copied token does not work elsewhere.
What visitors see
Section titled “What visitors see”Replies are not plain text. The widget renders the same rich surfaces the in-app chat does — cards, tables, statistics, badges, charts and images — so a result arrives as something readable rather than a blob of JSON.
The chat widget also renders real forms. When the assistant needs details before it can run something, the visitor gets labelled fields and a submit button instead of being asked to type values into a sentence. A few behaviours worth knowing:
- An incomplete submit comes back as a corrected form, with the missing fields marked, rather than an error.
- If a submit cannot reach us, the form stays editable and offers a retry — it never falsely reports success.
- A submitted form stays visible but frozen, marked as submitted, so the visitor can see what they sent.
The workflow widget displays results but has no forms; it collects what it needs up front.
Your visitor’s language
Section titled “Your visitor’s language”The widget speaks the visitor’s language, not yours. It works out which to use in this order: the language you configure, then the visitor’s browser, then English.
sapajaChat('init', { templateId: '…', token: '…', locale: 'fr' });Supported: en, fr, es, th, zh and zh-HK. Ordinary browser tags are
fine — fr-CA becomes French, zh-TW becomes Traditional Chinese. Anything
unrecognised falls back to English rather than failing.
This covers the widget’s own controls and everything the assistant generates: status lines, completion messages, result-card labels and the replies themselves. It applies per message, so a visitor who switches language mid-conversation gets the new one from their next message. Content already sent is never retranslated — a result card stays in the language it was built in.
If a conversation starts a long-running job, the language travels with it, so the completion message arrives in the language the visitor was using even if that is hours later.
One exception: text written by whoever built the workflow — field descriptions, clarification prompts and custom displays — appears as they wrote it. That is authored content rather than product copy, so it is not translated.
Building your own client instead
Section titled “Building your own client instead”You do not have to use the widgets. The embed endpoints are documented in the
REST API reference, and they take the same locale value
on each call — send it and you get the same behaviour, omit it and you get
English.
If something does not appear
Section titled “If something does not appear”- No microphone button. Voice needs a secure connection. On a page served over plain HTTP the browser will not grant microphone access at all, so the control is not shown. Serve your page over HTTPS.
- A component does not render. The widget only renders known component types and silently drops anything else, so a display it cannot understand is skipped rather than shown broken.
- The widget stops working. If the workspace that owns the embed no longer has an active subscription, the widget declines politely rather than showing your visitors a billing message.