How it works
1
Your app declares its tools
Each tool has a name, a description the agent reads, a JSON Schema for its arguments, and a kind: read, safe action or action. You register the tools with the web widget or the mobile SDK, together with the function that runs each one.
2
The agent is offered them
While the customer chats, the AI agent is offered the tools this customer’s app declared, when the channel has Use for chat on. On a channel with it off, the agent never sees them.
3
The agent calls a tool
A read runs at once, whenever the agent needs the data. A safe action runs at once too, but only when the customer asks for it. An action shows the customer a consent card first, and runs only after they tap Allow.
4
The result goes back to the agent
Your function’s return value reaches the agent, which uses it in its next reply. The conversation keeps a record of every call, visible to the customer and to your team in the inbox.
Turn it on for a channel
App tools are set per channel, in one place, for the chat and for voice calls. They are off by default: on every channel, a website’s or an Android or iOS app’s, Use for chat and Use for voice start off, and the agent gets no in-app tools until an admin turns Use for chat on. To turn them on:- In the cabinet, open the channel: Integrations > Web for a website, or Integrations > Mobile for an Android or iOS app. A Flutter app has an Android and an iOS channel: turn the switches on for both.
- Under In-app tools, turn on Use for chat: it lets the AI agent that answers the chats of this channel use the tools your website or app registers. Once it is on, the ready-made tools work too, all groups by default, and your developers turn groups off in code. To let the voice assistant use them during a call too, turn on Use for voice (see In a voice call). Use for voice needs Use for chat, because the voice assistant works inside the chat: turning chat off turns voice off too.
- Click Save changes.
The tools your developers register work on every channel. The ready-made tools need Android SDK 1.9.0 or ClaritySDK 1.6.0 for iOS in an app: the SDK version decides, not a cabinet setting.
Choose the kind
The kind says what a tool changes for the customer, and so when the agent may call it:
For example, “Which devices are on my account?” makes the agent call
list_devices and answer in the chat. “Show me my devices” opens the devices page with a safe_action. “Sign out the TV” puts a consent card in front of the customer before remove_device runs.
Declare your tools
Register the tools before the customer opens the chat, for example at startup. Registering the same name again replaces the tool in its place.
The agent is offered your tools in the order you register them, and it reaches for the ones listed first: register the tools it should use most, first.
If a customer has the chat open in more than one place, such as two browsers or your website and your app, the agent uses the tools of the chat they are writing in, and its calls run there.
The web widget adds
window.anecdoteLiveChatRegisterTool once its script has loaded. Call it from the snippet’s onload, after anecdoteLiveChatInit, or from window.onAnecdoteSuccess.
execute may return a value or a promise. A thrown error reaches the agent as the tool’s error message. anecdoteLiveChatRegisterTool returns false and logs the reason to the browser console when a declaration is invalid. window.anecdoteLiveChatUnregisterTool(name) removes a tool.
Argument and result schemas
Schemas use a subset of JSON Schema that every model provider accepts:- Keywords:
type,properties,required,items,enumanddescription. - Types:
object,array,string,number,integerandboolean. - At most 4 levels of nesting, 32 properties per object and 50
enumvalues. - A
descriptioninside a schema is at most 300 characters, and anenumvalue at most 100. - Property names follow the same rule as tool names.
confirmation_textis reserved for the consent card and cannot be an argument.
Limits
A tool that breaks a rule is left out, and the others are still offered. The web widget logs the reason to the browser console.
Ready-made tools
On a website, the web widget registers common tools for you, with no code: every group in the table below is on. It does so only once an admin has turned Use for chat on for the channel in the cabinet (see Turn it on for a channel); both switches are off by default, and with both off the widget registers no built-in tool. Which groups are on is set in your site’s code, not in the cabinet, so your developers keep control of it. AddinAppToolTemplates to the o object of the widget snippet:
- Nothing passed: all seven groups are on.
{ location: false, ... }: those groups are off, the rest stay on.{}orfalse: all built-in tools are off.
ClarityConfig.inAppToolTemplates by the same rules. There, siteSearch needs your website’s address and navigation the app’s screens before they offer anything. See Ready-made tools for Android and Ready-made tools for iOS. The Flutter plugin (since 0.6.0) offers siteSearch, navigation, diagnostics and, on Android, location; see Ready-made tools.
The kind of a tool decides whether the customer is asked first. A read changes nothing on screen and runs at once. A safe action (open a page, point at something, fill a field) runs at once, because the customer can see it and undo it. Important actions (kind action, such as pressing a button with click_element) run only after the customer allows them: they wait until the customer taps Allow on the card, or says yes in a call. get_location then also gets the browser’s own permission prompt.
To give the agent a tool of your own, register it with
window.anecdoteLiveChatRegisterTool (see Declare your tools). It works with or without the ready-made groups.
The default (every group on) makes 13 tools, so there is room for your own: a page offers at most 32. Your own tools always come first, so if the total is over 32 the ready-made ones that do not fit are left out; if your own tools alone are more than 32, the ones past 32 are left out too. Either way the widget names what it left out in the browser console.
Options
true turns a group on with its defaults. An object turns it on with options; {} is the same as true:
Opening pages
open_link opens a page of your site in one of three ways, set with navigation.mode:
While a page opens, the page dims slightly and a soft sheen passes over it, so the customer sees the agent is doing it.
In
handler mode, register how your app navigates once its router exists. A returned promise is awaited, and an error reaches the agent:
anecdote-live-chat:navigate event, and call done() or fail(reason) when the page has opened or could not:
open_link tells the agent the site has no handler. Your app has 10 seconds to open the page.
Sites drawn by JavaScript
The page tools read the page as the browser shows it, so they work the same on a page your server renders and on one a JavaScript app (React, Vue, Angular) draws.read_link and find_on_site read other pages by fetching them, and a fetch runs no scripts. On a single-page app that HTML is an empty shell, so:
read_linktells the agent the page cannot be read without opening it.find_on_sitewithout words reads your sitemap (/sitemap.xml, or the sitemapsrobots.txtnames), a static file even on a single-page app, so the agent learns which pages your site has.find_on_sitewith words uses your site’s own search when it can read the results. It takes, in order, thesearchUrloption, an OpenSearch description the page links to, or a schema.orgSearchAction. When there is none, or its results are drawn by JavaScript, it matches the words against the page addresses of your sitemap.
/help/return-policy) is what helps the agent most on a single-page app.
The tools stay within the limits of the browser and of your site:
- Your site only.
read_link,find_on_siteandopen_linkreach pages of the same origin as the page. Other sites are refused, and so is a page of yours that redirects to another site. - Public pages only.
read_linkandfind_on_sitefetch a page without the customer’s cookies, so the agent reads what a signed-out visitor sees and never the customer’s own account pages. - What
read_pagereturns without asking. The page’s title, its main heading, the text the customer selected, the text of its links and menu, the names of its forms, fields and buttons, and the error alerts it shows (role="alert",role="alertdialog",aria-live="assertive"). On an account page that text can hold the customer’s name or an order number (“Hi, Jane”, “Order #1234”). No tool reads what they typed or picked in a field. - The rest of the screen only with consent.
get_page_textreads the page’s whole visible text, account details included, and asks the customer first every time: dialogs, status lines, toasts and banners are part of that text, not ofread_page. It never reads what they typed or picked in a field, hidden elements or scripts. Withpage.pageText: falseit is left out. - Every field seen and filled, never read.
get_formlists every field of the page’s forms the customer sees: the standard ones (a name, an organization, an email, a phone number, an address) by theirautocompletetype, and the others (a date of birth, a free-text reason, a choice) by a field name taken from their label, with their kind, whether they are required and filled, and the choices a select or radio group offers. The agent fills any of them with what the customer says: it types a text or a date, picks a select option or a radio by the words the customer sees, and ticks or unticks a checkbox. It never returns what is typed or which choice is picked, never picks a file for the customer, and leaves out what is inside a private part (data-clarity-mask,data-clarity-exclude). - Errors as your page shows them.
get_formreads the conventions forms already use:aria-invalidwitharia-errormessageoraria-describedby, the browser’s own validation (:user-invalid), and the error classes of common UI kits (Bootstrap, Material UI, Ant Design, Chakra).read_pagereadsrole="alert"androle="status", live regions, open dialogs and toasts. Marking your errors this way, which accessibility asks for anyway, is all it needs. - One field at a time. The agent focuses a field (the page scrolls to it, it pulses twice and stays highlighted in your widget’s primary colour), asks for its value and fills it, then moves to the next. The customer can also type into the highlighted field and tell the agent when done. Several values given at once are filled together.
fill_form_fieldstakes one field flat (fieldandvalue), the shape a light voice model manages, or several in afieldslist; a call with neither or both is refused. The highlight goes when the field is filled, when the customer turns to something else, or after two quiet minutes. In a voice call the agent spells an email or a phone number back before filling it.
anecdoteLiveChatInit again applies its own inAppToolTemplates by the same rule: with nothing passed, all seven groups are on again.
Pressing for the customer
click_element presses an element by the name the customer sees, the same names read_page lists and show_on_page points at. It is an action, so it runs only after the customer taps Allow on the card (its line names the element, such as Press “Save profile”), or says yes in a voice call. The page scrolls to the element, which is checked again right before the press, and then pressed with a click, the same event your page’s code gets from a real click. The agent gets back pressed: true and the element’s label, and the new url when the address changed (a router that draws the next page).
A press that loads another page (a plain link, or a form your page lets the browser send) is held until the result has reached the agent, then made, and the chat opens again on the new page, as with open_link in reload mode. During a voice call such a press is refused, because the load would end the call.
It presses nothing, and tells the agent to point at the element with show_on_page and ask the customer to press it themselves, when the element:
- is not on the page (the agent is then told the names it can use), is hidden, or is not a button, link or other control;
- is disabled (
disabled, oraria-disabled="true"); - is a field to type in (a text input, a text area, a select): the agent is told to use
focus_form_fieldorfill_form_fieldsinstead; - picks a file (
input type="file"); - opens a new window (
target="_blank"on a link or a form) or another app (mailto:,tel:), which browsers allow only from a real press; - leads to another site, or sends its form to one;
- is inside a frame, which the page cannot reach;
- is inside an element marked private with
data-clarity-maskordata-clarity-exclude; - carries
data-clarity-no-click, or sits inside an element that does.
data-clarity-no-click:
"inAppToolTemplates": { "click": false }.
What the customer sees
- Read: while the tool runs, the chat shows a short “checking in the app” status.
- Safe action: it runs at once, and the change shows on the page.
- Action: the chat shows a consent card. Each step on it is one sentence the agent writes, such as “Sign out the living room TV”. Under it are the tool’s name and the exact arguments, which the agent cannot word. The customer taps Allow or Decline.
get_location, and the reply names the nearest store. A plain change, such as a new phone number, gets a short confirmation.
The card belongs to the conversation the agent asked in. When one request takes several actions, such as “add the Kids pack” and “add the Cinema pack”, the customer gets one card that lists every step. One Allow runs the steps one after another, in the order the agent asked for them. If a step fails, the steps after it do not run. One Decline declines them all.
A safe action runs at once, without a card. If the agent has already put a card in front of the customer in the same reply, the safe action joins that card as a step, so the steps keep their order.
Write descriptions that say when the agent should use each tool. An action or a safe action changes something for the customer and returns nothing for the agent to read, so the agent calls it only when the customer asks. To let the agent look something up, give it a read tool. For example, add a read tool that reads a page without opening it, next to a safe action that opens the page.
Every call leaves a line in the conversation with the tool and its outcome. Your team sees the same record in the ticket.
In a mobile app, the chat steps aside
In the iOS and Android SDKs the chat is a sheet over your app, so a tool that opens a screen would do it out of sight. Give such a tool areveal: the chat steps aside with a loader while the tool runs, the customer sees the screen open, and the chat comes back. See Show what the tool did in the iOS and Android guides, and In-app tools in the Flutter guide.
An Android app opens the plan screen while the chat steps aside
In a mobile app, confirm once on the device
An app can mark an action as needing its own security check, such as Face ID, a fingerprint or a PIN. When the customer taps Allow on a card with such an action, the app runs the check once for the whole card, before anything runs: a card of three steps asks once. If the check does not pass, nothing runs and the card asks again. See Confirm once in the iOS and Android guides; the Flutter plugin has the samerequiresSecurityCheck and Clarity.setSecurityCheck.
In a voice call
When your widget offers voice calling, the voice assistant can use the same tools during a call. A customer can say “show me my devices” or “sign out the TV” and the assistant does it in your website for them, and says what it found or what changed. This also helps a customer who cannot easily see or use the screen.- In the cabinet, open the channel’s settings, where voice calling is turned on.
- Under In-app tools, turn on Use for chat and Use for voice. Voice is greyed out while chat is off.
- Click Save changes.
- Read: the assistant looks the data up and tells the customer the answer.
- Safe action: it runs at once, for example the devices page opens behind the call.
- Action: the call steps up and makes room for a short confirmation with Allow and Decline, with Allow focused, so a keyboard or screen reader user can answer with one key, and the assistant says once what the action will do and asks whether to go ahead. The confirmation lists each step on its own line. The customer can tap Allow, or just say yes. Only a clear yes said once the confirmation is up counts: a question, a hesitation, the request that led to the action or a yes said before never allows it. All the actions of one request share one confirmation. When they answer, the assistant tells them the outcome. A confirmation still waiting when the call ends is declined.
safe_action that chooses the value and applies it, rather than one tool to choose and another to press the apply button.
If the chat is open in several tabs, only the tab the call is in runs the action. The conversation keeps the same record of every tool call as in a chat, marked In a voice call. The records reach the chat’s ticket when the call ends, with the call’s transcript, each at the time it was made, so a call placed before the customer wrote anything is recorded too. When the customer answered out loud, the record says Allowed by voice or Declined by voice, with the words they said.
In a mobile app, the call folds to a bubble
On a website the call collapses to a bubble over your page in the same way: when the assistant points at something withshow_on_page, a call in the panel collapses, and the bubble moves off what is pointed at. See Collapse the call to a bubble.
On a website, a card opens a call that is a bubble, so the customer can answer it. Once they allow it, the call goes back to the bubble when every step on the card has collapseCallOnAllow, and your page is in view while the steps run. The ready-made actions have it unless you turn it off with <group>.collapseCallOnAllow: false. A call the customer opened themselves stays open: only the call the card opened goes back, and only for that card’s Allow.
In the iOS and Android SDKs a call can collapse to a bubble over your app, so the customer keeps using the app while they talk. During a call in the sheet, a tool with a reveal collapses the call this way instead of stepping the chat aside, and the customer sees the screen open; a full-screen chat stays as it is, and the screen opens behind the call. An action that shows its result in your app can fold the call too: register it with collapseCallOnAllow, and once the customer allows the card, the call folds back to its bubble while the steps run. The bubble comes back as the call when the assistant needs another answer on screen. See Voice calls in the iOS and Android guides.
An Android app: the customer allows a purchase, and the call folds back to its bubble
Security
Declarations, arguments and results all come from the customer’s device, so treat them like any other input from a browser or app:- Authorize in your API. A tool can do only what your API lets this customer do. Check every change on your server, as you would for the customer clicking the button themselves.
- Keep it least-privilege. Expose what a support conversation needs. Make anything that changes the customer’s data, money or settings an
action, so the customer confirms it. Keepsafe_actionfor what only changes the screen. - The agent treats app data as data. Clarity marks every result and every error from your app as untrusted before the agent sees it, and the agent is told never to follow instructions inside it. A description is shown to the agent as your app’s description of the tool, capped in length, and an app tool cannot replace one of the agent’s own tools.
- Nothing is unlocked by a result. A result never grants the agent access to anything on the Clarity side, such as a tool your team configured or another customer’s data.
- The kind you register is the kind that runs. Clarity refuses a call below the kind your page or app registered, so a declaration altered on its way cannot turn an
actioninto areadand skip the customer’s Allow. - One Allow covers the steps it showed. Allow starts only the steps the card showed when the customer tapped it. A step that reached the card later asks again on a card of its own.
- Only your page and the chat reach your tools. The web widget takes tools and events only from the page that embeds it. The Android SDK (since 1.9.0) and the iOS SDK (since 1.6.0) do the same: only the chat page itself reaches your app, and a script inside a frame of the chat cannot call your tools.
- Logs keep out the data. Clarity logs the tool name and the call id, never the arguments, the result, or the chat’s session.