Build a widget
Create a widget with declared fields and example data, check its code, and show it from an API action or a matching widget condition.
Build a widget to show selected data as a card under a reply. You need an agent and permission to edit it. For API-backed data, create an API connection to an API that returns JSON.
Create a widget
Open the builder
Go to your agent’s Build > Widgets and select Create widget. A new widget opens to the Start from a template gallery. Select a template or Start from scratch. Enter a Widget name. Names must be unique within this agent. The widget is not created until you save it.
The top bar shows the name, Enabled, Unsaved changes, code-check status, action usage, Save, and Widget options. Turn on Enabled to use the widget from its own condition or a Custom API action.
The editor has four tabs:
| Tab | Purpose |
|---|---|
| Code | Write the card using the supported components and expressions. |
| Functions | Define what happens when a visitor selects a button or list item. |
| States | Define when sections of the card appear. |
| Settings | Choose when the widget appears on its own. |
Under Code, the bottom panel contains Fields, Default, and a tab for each named example. The preview is beside the editor on wide screens and below it on smaller screens.
Write the card
Replace the code with one expression rooted in <Card>. Put text in a value prop, rather than between tags. Do not add imports, variable declarations, or a component function.
<Card>
<Title value="Your order" />
<Text value={`Order ${order.number}`} />
<Text value={order.status === "Shipped" ? "On its way" : "Preparing"} />
</Card>Field reads use braces: value={status} reads a top-level field, value={order.status} reads a nested field, and value={items[0].name} reads the first list item. Variables set by functions use the same syntax, such as value={pickedName}.
Use .map() to repeat components. Its body must be an expression, with one item parameter and an optional index parameter. Other method calls are not supported.
<Card>
<ListView>
{items.map((item) => (
<ListViewItem>
<Text value={item.name} />
</ListViewItem>
))}
</ListView>
</Card>Use template strings to combine text and data, and ternaries to choose a value. Comparisons, &&, ||, and ! are also supported. See the component reference and functions and states.
The editor helps you write the code:
-
Suggestions: type
<to see the components and your state names. Inside a tag, type a letter to see that component’s props. Inside a prop’s quotes, see its allowed values. InsidefunctionName: "", see your function names, and inside braces, see your field keys. -
Format: select Format, or press Shift+Alt+F in the editor, to fix the indentation and line breaks. Formatting does not change what the widget shows, and it keeps your comments. Format is not available while the code has errors.
-
Component reference: select Component reference under the editor to open the component reference in a new tab.
<
< title="Declare the fields">
<>
Go to Fields and select Add field for each value the card reads. For the order card, use:
| Field | Type | Description |
|---|---|---|
order.number |
Text | The visitor’s order number. |
order.status |
Text | The current delivery status. |
Types are Text, Number, Yes/no, Object, and List. Fields have a key, type, and optional description; they do not have a separate label. Use List for items in the repeated-item example.
Keys use dot paths. Start with a letter or underscore, followed by letters, digits, or underscores. Later path segments can contain letters, digits, or underscores. Duplicate keys and the segments __proto__, prototype, and constructor are refused.
Declare only visitor-safe data. An Object or List field includes its whole value. Function-created variables do not need a data field declaration unless you also want to populate their initial values from action data.
Add preview data
Go to Default and enter a JSON object. Fill from fields replaces it with a starting structure based on your fields.
{
"order": {
"number": "Not provided",
"status": "Preparing"
}
}Default values also reach live visitors when neither action inputs nor the API supplies a value. Do not use private customer data as a default.
Select Add example to create a named example. Enter an Example name, such as Shipped, and its JSON:
{
"order": {
"number": "A-1234",
"status": "Shipped"
}
}Named examples only affect the preview. They merge over the default example, so you can provide only the values you want to change. Select the Preview data pills to switch between Default and named examples. Reset clears preview variables, dismissal, and preview messages. Changing the preview data or definition also resets it.
In the preview, Send message shows a sample visitor message without starting an agent turn. Open link opens the configured URL in a new tab. When a widget includes a Call API function, the preview header shows a Call API result: Success | Failure toggle. Setting the toggle lets you test both outcomes in the preview without making live network requests. In the Functions tab, you can select Run to execute the endpoint directly with test inputs and inspect real return fields and responses.
Check and save
Check the preview and the code status. Code checked means the local parser accepted the code; saving also runs server validation of components, props, functions, and limits.
Parser errors show a location such as Line 1, column 1. These are actual parser messages:
| Message | What to change |
|---|---|
Check the widget syntax. |
Fix incomplete or malformed markup. |
Widget code must start with <Card>. |
Use a Card as the root component. |
Only .map() is allowed. |
Remove other function or method calls. |
Use one or two simple .map() parameters and an expression body. |
Remove a block body or complex parameters. |
Use Text or Caption with a value prop for text. |
Move text into a component’s value prop. |
Server validation can show these messages. Server errors do not include parser line and column locations:
| Message | What to change |
|---|---|
<div> is not a widget component. |
Choose an allowed component. |
<Text> has no prop "className". |
Remove unsupported props. |
<Button> cannot have children. |
Use the label prop. |
Function "pick" is not defined. |
Define the named function in Functions. |
Widget trees allow at most 2000 nodes and 40 levels. |
Reduce the tree’s size or nesting. |
Select Save, or press ⌘+S on macOS or Ctrl+S on other systems. Fix any field, example, or code errors and save again. Invalid example JSON shows Use a valid JSON object..
If you navigate away with changes, Leave without saving? offers Keep editing or Leave page. Leaving discards unsaved changes.
Choose when the widget appears
Make sure Enabled is on in the top bar. Then go to Settings and write a When to show condition if you want the widget to appear on its own. Describe the visitor’s goal, such as “When the visitor wants to book a call or see open times.” Leave the condition empty if an action should be the only thing that shows the widget. A widget with a condition can appear in the web widget, Public Chat, and Playground. See Trigger Conditions.
Attach the widget to an action
Go to Build > Actions and open or create a Custom API action. Select an API connection, then choose your saved widget in the Widget card. The action calls the API and shows the widget after a successful JSON response if the widget is enabled.
Create widget and Edit widget open the builder in a new tab. Save there, then return to the action to select it. Save the action and test a conversation in the Playground. The action editor’s test request does not render widgets.
The saved widget is available to this agent’s actions. A matching conversation can show it under the reply in the web widget, Public Chat, or Playground.
Start from a template
Templates are starting points stored in the builder. They use no AI and no credits.
Open the template gallery
For a new widget, go to Build > Widgets and select Create widget. The Start from a template gallery shows six template cards and Start from scratch.
For an existing widget, open it and select Widget options > Start from a template in the top bar. The gallery opens in a dialog.
Preview and apply a template
Select a card to preview it, then select Use template. For an existing widget, the builder asks Replace this widget’s code, fields, examples, functions and states?. Select Replace widget to confirm.
Applying a template fills in the code, fields, examples, functions, and states. If a new widget still has the default name, its name becomes the template title.
Connect the template to your data
Go to Fields to check the field names. Adjust the widget and save it, then attach it to a Custom API action or set its When to show condition. Match the API response to the template’s fields. Test the result in the Playground.
The widget now uses the template as its starting point. You can edit its code, fields, examples, functions, and states.
| Template | What it shows | Fields it expects |
|---|---|---|
| Product list | Search results with image, price, stock and a View link. | query, count, products |
| Order tracker | Order status, items, a delay notice and tracking. | order |
| Pricing plans | Plans with price, key features and a Choose plan link. | plans |
| Appointment slots | Pick a time, then book it in the chat. | date, slots, picked |
| Contact card | Support hours, email and phone links, talk to a person. | hours, replyTime, online, email, phone, contactUrl, callUrl |
| Quick replies | A short question with buttons that answer for the visitor. | question, replies |
Delete a widget
Remove action references
Check the widget’s Used by names. Remove or replace its selection in every action, including disabled actions, and save those actions. Deletion is refused while any action uses the widget; the refusal names the actions.
Delete the saved widget
Go to Build > Widgets, open the widget’s options, and select Delete widget. You can also use Widget options in the builder. Select Delete to confirm. Replies that already displayed it keep their copy.
Limits
| Item | Limit |
|---|---|
| Widget name | 100 characters; unique within the agent |
| Source | 20,000 characters |
| Component and expression tree | 2,000 nodes and 40 levels; root must be Card |
| Literal strings in the tree | 2,000 characters each |
| Fields | 50 |
| Field description | 500 characters |
| Named examples | 10; names up to 60 characters |
| States | 20; names match ^[A-Z][A-Za-z0-9]{0,39}$ |
| Groups per state | 10 |
| Conditions per group | 20; comparison value up to 500 characters |
| Functions | 20; names match ^[A-Za-z_][A-Za-z0-9_]{0,63}$ |
| Open link URL | 2,048 characters; starts with http:// or https:// |
| Function message | 4,000 characters |
| Variable value template | 1,000 characters |