Clip failover: this page configures the card with a poster and two silent loops of a presenter (a Pexels clip, source and license in AVATAR-MEDIA.md): the listening loop plays before the call and the speaking loop while the agent talks. Once the call connects and the agent has its avatar setting on, the live AI avatar replaces the clips, exactly as on /avatar. For your own site, point the three URLs at your cleared poster and clips.
This page is the host site: the call lives in the card below. No build
step — the page loads widget.bundle.js directly with a
<script> tag. Every press of Call asks
example/server.py for a fresh room, so the short-lived LiveKit token
is never stale.
The widget is the optional component shipped by the SDK. Restyle it by overriding the tokens on .ht-widget — see
“Optional widget” in README.md.
“Call details” inside the widget holds the dynamic variables the agent receives;
the list itself is declared once in example/scenarios/ and chosen
by the server, next to the agent it belongs to. Call talks,
Chat runs the same conversation with no microphone and no audio. The second
layout — the call as the whole page — is at /call, and
/free is this same widget with nothing configured: the agent
and every variable are typed in. /avatar shows avatar mode. /file replaces the
microphone with an mp3 or wav file.
.env on that server — see
.env.example. Neither this page nor the SDK ever sees the key, which is
the shape a production integration has too: your backend calls
POST /v1/calls/web and returns just the session JSON to the browser. The
variable values typed into the widget are accepted only for the keys the server
declares — the browser names values, never the contract.