This page assumes you have already built a component. If not, start with Components.
Fetch data before showing
Fetch data before showing calls your API at the moment the assistant sends the component, and binds the JSON response so blocks can render it. Use it for anything that must be current, such as live pricing, the user’s open orders, or available inventory. Configure the request in the component’s ADVANCED section: a method (GET, POST, PUT or PATCH), a URL, and free-form rows for headers, query params and body. There is no separate auth section, so add an Authorization header row.
The parsed response is bound to api_res:
Inside a block prop you can interpolate a binding into a longer string, such as
₹${{plan.premium}}/mo. When the whole value is a single binding the raw typed value is kept, so arrays and objects survive intact.
api_res is only a valid binding anywhere in the component when this fetch is configured. Without it, saving fails with an undeclared-source error.
Send data when a button is tapped
Call an API on response fires when the user taps a button, and sends what they tapped or typed. It takes the same request shape as the fetch above. These bindings are available in the URL, headers, query and body:
Anything else is rejected when you save, so a typo surfaces immediately rather than failing silently at runtime.
A single button can carry its own API call, which overrides the component-level one for that tap. The override is matched by Action ID, so a button inside a repeated list, whose Action ID is itself a binding, cannot be matched and falls back to the component-level request.
Send data when a form is submitted
There is no separate submit action. A button set to Send to agent collects the named inputs of its nearest ancestorform, or of the whole component if there is no form, exactly like HTML. That is what the inspector means by “Inside a Form, ‘Send to agent’ also submits the form’s inputs.”
Required fields and email formats are validated in the browser first, over the inputs that are currently visible. Anything hidden by a condition is skipped. The assistant then receives:
Fire an event on your page
Set a button’s when tapped to Page event and give it an Event ID. Tapping dispatches aCustomEvent on window, which your own page handles however you like: open a modal, scroll to a section, start a checkout.
a-z, 0-9, _, - and : survive, so ringg:open_pricing is valid as typed.
A page event does not reach the assistant. It fires on your page only. If the assistant needs to know the user acted, use a Send to agent button instead.
Open a link
Set when tapped to Open a link for anything that leaves the chat: a brochure, a policy PDF, a payment page, a phone number. A brochure download is the common case. Give the button a label, a URL, and a target:${{api_res.brochure_url}}.
Two rules the builder enforces when you save:
- The scheme must be
https:,mailto:ortel:. Plainhttpis rejected. - The URL must be either a plain literal or one whole
${{binding}}. A literal host with a binding spliced into it, such ashttps://cdn.example.com/${{api_res.id}}.pdf, is rejected. Return the complete URL from your API instead.
Render an image
Theimage block takes a url, not src, plus optional alt, align, width and height. Give it a width or height, or it renders as a small thumbnail.
Image URLs are held to the strictest rule of any prop: https only, and the same literal-or-single-binding rule as links. So a product shot driven by your API works:
What you can bind to
Parameters
Parameters are the blanks the assistant fills in when it shows a component, such as the plans to compare or the order to display. Add them under Parameters, with a key, a description and a type ofstring, number, boolean, array or object. Keys are sanitized to a-z, 0-9 and _.
Only dynamic parameters are described to the assistant, and its test value doubles as the example shape it is shown. Give each one a description that says what belongs in it, because that description is what the assistant reads.
If a required dynamic parameter arrives missing or empty, the component is not sent and the assistant is told to say something instead, so a component never renders half-populated.
Leave Parameters empty and the component simply uses conversation values as they come.
Agent actions
A component is not the only way to reach your page. The assistant can also dispatch a browser event directly, with no card or form involved, which suits things the user never needs to see or tap: focusing an input, opening a modal, scrolling to a section.Where to set this up. Open your agent and go to Embed & Widgets → Legacy widgets → Execute DOM Action (
execute_dom_action). Each entry under Actions is one event the agent can dispatch.
At runtime the agent decides during a conversation when to fire one of its configured actions, the widget dispatches a
CustomEvent on window using the Event ID as the event name, and your listener runs. Actions only fire during an active conversation.
eventLogs to see a pill in the chat thread each time an action fires. It is purely a visual aid, and actions fire the same way either way:
Looking for widget state events such as open, close, conversation start or feedback? Those are separate. See Widget Lifecycle Events.
Limits and QA notes
Bindings resolve and repeated blocks expand on the server, before anything reaches the browser, so the user never sees an unresolved
${{…}}.A component resolves to at most 500 nodes. A repeat over a long list is capped by
max_items, not by the source array.Unresolvable optional props are dropped and empty containers are pruned, so a missing API field degrades quietly instead of rendering blank.
Test with the fetch pointed at your real endpoint. A request that fails means the component is sent without
api_res, and any block that depended on it disappears.Components render during voice calls too, but they are designed for chat. Confirm the flow still makes sense if the user is only listening.
After renaming a component, update every
@[[…]] mention in the prompt. The rename is blocked until you do.For agent actions, add an Event ID, attach a matching listener, and confirm it fires during a test conversation. If you configured a Default Payload, verify
event.detail carries those fields.