Install
Add the script before the closing </body> tag on every page where the chat should appear. Your site ID is on the website's page in the dashboard.
<script
src="https://api.recursivechat.dev/widget.js"
data-site="wgt_your_site_id"
async
></script>- The script is small, has no dependencies and loads without blocking your page.
- The chat lives in a closed shadow DOM, so your CSS cannot affect it and its CSS cannot affect you.
- Colours, position, avatar and header text are set in the dashboard, under the agent’s Settings, Appearance. Changes show the next time a page loads.
Calling the API before it loads
Commands are calls to window.RecursiveChat. Add this stub before your own code and you can call commands straight away: they are queued and run once the widget has loaded.
window.RecursiveChat = window.RecursiveChat || function () {
(window.RecursiveChat.q = window.RecursiveChat.q || []).push(arguments);
};Commands
| Command | What it does |
|---|---|
open | Opens the chat panel. |
close | Closes the chat panel. |
toggle | Opens the panel if closed, closes it if open. |
sendMessage | Opens the chat and sends a message as the visitor. Takes the message text. |
setMetadata | Attaches details to the visitor, such as their plan. See Visitor details. |
identify | Links the visitor to your signed in user. See Signed identity. |
reset | Forgets the visitor in this browser and closes the chat. Call it when a user signs out. |
hide | Removes the chat button and panel from the page until you call show. |
show | Brings the chat back after hide. |
// Your own help button
document.querySelector('#help').addEventListener('click', () => {
RecursiveChat('open');
});
// Start a conversation with a question
RecursiveChat('sendMessage', 'I need help with my invoice');Visitor details
Details you attach are shown to your team next to the conversation in the Inbox. The AI sees only the fields you tick in the agent's Settings, under What the AI knows about the visitor.
RecursiveChat('setMetadata', {
plan: 'Pro',
is_trial: false,
seats: 4,
});- Keys use letters, numbers and underscores, start with a letter and are up to 40 characters, such as
planoris_trial. - Values are text (up to 500 characters), numbers or true and false.
- Up to 25 fields per call. Each call merges into what you sent before.
- Metadata is not verified, so use it for context, never for decisions about access or money.
Signed identity
Identify links a visitor to a user in your own system. The same person then keeps one conversation history on every device, their name and email show in the Inbox, and the chat never asks them for their email.
To stop anyone pretending to be another customer, your server signs the user's ID with your site's identity secret using HMAC-SHA256, and RecursiveChat checks the signature. The secret is on the website's page in the dashboard.
import { createHmac } from 'node:crypto';
// Your site's identity secret, from Websites > your site in the dashboard.
// Keep it on the server: never send it to the browser.
const signature = createHmac('sha256', process.env.RECURSIVECHAT_IDENTITY_SECRET)
.update(String(user.id))
.digest('hex');import hashlib, hmac, os
signature = hmac.new(
os.environ["RECURSIVECHAT_IDENTITY_SECRET"].encode(),
str(user.id).encode(),
hashlib.sha256,
).hexdigest()$signature = hash_hmac(
'sha256',
(string) $user->id,
getenv('RECURSIVECHAT_IDENTITY_SECRET')
);// In the browser, once the user is signed in
RecursiveChat('identify', {
externalCustomerId: String(user.id),
signature, // from your server
name: user.name, // optional
email: user.email, // optional
metadata: { plan: user.plan }, // optional
});
// When they sign out
RecursiveChat('reset');externalCustomerIdis your user ID as text, up to 128 characters. Sign exactly the same string you send.signatureis the 64 character hex digest.name,email,phoneandmetadataare optional.
Single page apps
In apps that change pages without a full reload, the chat stays on screen between routes. Use hide and show to keep it only where you want it.
// Show the chat on public pages, hide it inside your app
router.afterEach((to) => {
RecursiveChat(to.path.startsWith('/app') ? 'hide' : 'show');
});Privacy and security
- The widget holds no secrets. It talks to our API with a short lived token that only works for that visitor’s own conversation.
- Visitors are anonymous until they give an email or you call identify.
- Page addresses are recorded so your team can see where a visitor is, with tokens and similar sensitive query parameters removed.