Overview
Both<tavus-widget> and <tavus-embed> support two-way communication with the host page:
- Element → page: the element dispatches
CustomEvents (withbubbles: trueandcomposed: true) for conversation lifecycle, tool calls, and protocol messages. - Page → element: the element exposes methods for starting, creating, ending, and messaging the conversation (
startConversation(),endConversation(), …).
TavusIntegration helper exported from @tavus/widget and @tavus/embed.
Events
Listen on the element itself, or ondocument (events bubble out of the shadow DOM):
tavus:protocol-message carries the raw Interaction Events protocol - detail.event_type values such as conversation.utterance, conversation.tool_call, conversation.started_speaking, and conversation.stopped_speaking match the schemas documented there. For speaking state, check detail.properties.role ("user", "pal", or legacy "replica"). See Started/Stopped Speaking Event.Reading a transcript
Utterances arrive ontavus:protocol-message with detail.event_type === "conversation.utterance". detail.properties.role is "user" for the visitor or "replica" for the PAL, and detail.properties.speech is the text. Two kinds of utterance share that event type: a complete utterance, which carries no final field, and streaming partials of the same sentence, which carry a boolean final field (false while the sentence grows) and may carry is_interrupted. Keep only the ones without a final field, or a transcript shows every partial as its own line.
Magic Canvas card taps are not emitted as
tavus:* host events. Only an API-created conversation with a callback_url receives them as canvas.interaction events. Hosted embed and widget conversations do not have a callback_url. See Canvas interactions.Imperative API
The element installs its methods once its configuration has loaded, so wait fortavus:ready before calling them:
Host-provided devices
When your page renders its own device preview, skip the built-in haircheck and pass the selected devices into the call:element.tavus
element.tavus.sendChat(text) sends a chat message into the conversation as the visitor, and element.tavus.sendMessage(interaction) sends a typed protocol interaction.
Interactions
sendMessage accepts the same interaction shapes as the Interactions Protocol:
TavusIntegration helper (npm)
npm consumers get a typed wrapper around the element from the same package as the registration side effect:
The helper looks up the element by tag name in the DOM, so construct it (or make the first call) after the element exists on the page.
TavusIntegration is bundled into the ESM builds of @tavus/widget and @tavus/embed - no extra install. The CDN (IIFE) build stays a pure side-effect drop-in; CDN pages use the DOM APIs above instead.Letting the PAL act on the page
The PAL cannot touch your page on its own. Every action it can take there, such as adding to a cart, opening a product, filling a form or booking a slot, is a tool defined on the PAL and implemented by your page. Two halves, and both have to exist:- A tool on the PAL. Create it in the PAL Maker or with the Tools API and attach it to the PAL behind the deployment. Give it a name, a description that tells the PAL when to use it, a JSON schema for its parameters, and
delivery: { "app_message": true }, which is the default and means the call is sent to the page over the conversation’s data channel. Seton_resolvetogenerate_responsewhen the PAL should speak from your result (an availability check, a price), or leave the defaultfire_and_forgetfor side effects it does not need to narrate. See LLM tool calling and Tool delivery. - A handler on the page. The call arrives as
tavus:tool-callwith the tool’sname, itsargumentsas a JSON string written for the schema, and atool_call_id. The element does not validate the arguments, so parse them in a try/catch and check the values before acting. Do the work, then sendconversation.tool_resultwith the same id. Without a matching id the call times out on the server.
output is a string or an object. Send status: "error" and the PAL acknowledges the failure instead of using the result.
The PAL only knows about the page what the page tells it. Pass the starting state in conversational-context (the open product, the visitor’s name, what is already in the cart) and send conversation.append_llm_context when it changes during the call, so the PAL’s suggestions match what the visitor sees. Event shapes: tool call and tool result.
Examples
Two pages in tavus-examples use this API end to end: embed-programmatic mounts the element from the page’s own button, starts ontavus:ready and sends suggested questions with conversation.respond; embed-session-flow pre-creates the conversation with createConversation() and builds a live transcript from tavus:protocol-message. See Examples.
