Skip to main content
Pass callbacks in the WebCall config to follow the call from your own code: update your UI, log analytics, or save the transcript. All callbacks are optional, and all of them also work when you use the built-in widget.

Lifecycle callbacks

PhoneStatus values

Errors

onError receives the raw error, which can include the API’s message. The built-in window shows a generic message instead, such as Unable to start the call. Please try again., so internal details never reach visitors. A refused call start looks like this:
See Troubleshooting for each message.

Transcript

The transcript streams in while the call runs. Pick the callback that fits how your UI stores state:
  • onTranscriptMessage fires once for each message that is new or changed. Use it to append or update one row.
  • onTranscriptChanged fires with the full, de-duplicated list (the most recent 500 messages) whenever anything changed. Use it when you keep the transcript as one piece of state, such as setMessages(messages) in React.
Both fire in the same tick with the same data, so you usually need only one. A message counts as changed when its content, skip, nodeId, timestamp, widget or toolCall differs from the last version with the same id. Messages update in place as the agent speaks, so always key by id.
getTranscriptMessages() returns the current snapshot on demand, and an empty array once the call ends. To keep the final transcript, store the last list from onTranscriptChanged.

TranscriptMessage

string
Stable ID for the message. The same ID is sent again when the message changes.
string
assistant for the agent, user for the visitor. Other roles can appear for system and tool entries; filter on these two for a chat view.
string
The message text.
number
When the message was created.
string
The stream event type, usually transcript.
boolean
true on an agent message that was generated but never spoken, for example because the visitor interrupted before its audio started. The built-in widget hides these; hide them in your UI too.
string
The script block the message belongs to.
object | null
Present when the agent shows an in-call form with this message.
string
On a visitor’s form answer, the id of the form message it answers.
unknown
Present on entries that record an action the agent ran.
The stream can include additional fields. Ignore any you don’t use.

Show a clean chat

Form answers and typed messages

onWidgetInputSent fires when the visitor submits a message or a form answer from the built-in UI, before it is sent:
For form answers, content is a JSON string of the field values. The first message that starts a text conversation also fires this callback, without a widgetMessageId.

A form, end to end

When the script reaches a widget step, the form arrives as an agent message with a widget:
The built-in UI renders formElements and, on Submit, fires onWidgetInputSent with the answers keyed by each field’s Name, then sends them:
If you render forms yourself (a hidden widget or headless setup), send the answer with sendInput(), passing the form message’s id:
Send '{}' to skip. The answer then appears in the transcript as a user message whose correspondingToMessageId is msg_42, and the agent continues with it. Skip messages where widget.viewOnly is true; they expect no answer.

React example

CallTranscript.tsx
This assumes the SDK script is already on the page. To load it on demand, see Headless and React Native.

Methods

Start, end and control the call.

Watch events live

The playground shows an event log and the raw transcript during a test call.