Control the avatar and read its live status from your own components.
useAvatar gives you everything you need to build custom controls: methods to
start, stop, mute, and send speech, plus live status flags that update as the
session changes.
Call it inside any component nested under <AvatarProvider>.
That button is correct from the first render. It says "Start conversation"
while the avatar is still loading — and it works, because start() waits the
load out for you.
Two independent axes. Never infer one from the other: isIdle does not mean
there is no avatar, and isReady does not mean you are in a call. See
State & Lifecycle.
| Prop | Type | Default | Description |
|---|---|---|---|
isReadyOptional | boolean | No default | The avatar is on screen and animating. Unaffected by a session starting or ending. |
isLoadingOptional | boolean | No default | The avatar is still coming up — resolving config, or resolved with the canvas unfinished. |
isFailedOptional | boolean | No default | The avatar could not be loaded; nothing is on screen. Survives a session ending, so label the action "Retry" rather than "Connect". |
| Prop | Type | Default | Description |
|---|---|---|---|
isIdleOptional | boolean | No default | No session; start() is available. True while the avatar is still loading, since start() waits the load out. |
isConnectingOptional | boolean | No default | start() is in flight — token, config, socket, and init ack, end to end. |
isConnectedOptional | boolean | No default | The session is live. The turn states below only apply from here. |
| Prop | Type | Default | Description |
|---|---|---|---|
isListeningOptional | boolean | No default | Waiting for the user's voice. Call mode. |
isThinkingOptional | boolean | No default | The server is working out the reply, between listening and speaking. |
isSpeakingOptional | boolean | No default | The avatar is talking, with lip-sync running. |
isResponseSlowOptional | boolean | No default | The current turn is taking unusually long. Advisory — the turn is fine, just slow. Auto-clears when speech starts or the turn ends. The built-in thinking indicator renders off this. |
| Prop | Type | Default | Description |
|---|---|---|---|
isMicMutedOptional | boolean | No default | The user's mic is muted — outbound audio is dropped, so the server hears silence. Call mode. |
isSpeakerMutedOptional | boolean | No default | The avatar's audio is muted. Playback is silent but lip-sync still animates. |
isPushToTalkOptional | boolean | No default | turnTaking.mode is "push-to-talk". Static for the session. |
isTalkingOptional | boolean | No default | The user is holding the talk button, so their audio is reaching the server. |
| Prop | Type | Default | Description |
|---|---|---|---|
errorOptional | AvatarError | null | No default | The most recent error, or null. Sticky — it stays until the next start(), and never clears on a timer. |
noticeOptional | SessionNotice | null | No default | The last server notice (limit, plan, test key). Not an error — the session is ending gracefully. Drive your upgrade CTA off this. |
healthOptional | ConnectionHealth | No default | Live connection health. health.concern is the blame-resolved banner state (null when all is well); health.services is the raw per-service map. |
transcriptOptional | TranscriptEntry[] | No default | Conversation lines, oldest first. Empty unless transcript.enabled. |
availableActionsOptional | string[] | No default | Gesture names the loaded rig advertises. |
avatarIdOptional | string | undefined | No default | The currently loaded avatar's ID. |
controlsOptional | { enabled: boolean; stopSpeaking?: boolean } | No default | Whether the built-in control bar is shown, and whether it includes the stop-speaking button. |
Open the session. In call mode this requests microphone permission. If the
avatar is still loading, start() waits for it rather than failing.
Call start() from a real click or tap. A session started outside a user
gesture connects but stays mute — browsers block audio that no one asked for.
End the session. The avatar stays painted, so restarting is cheap and isIdle
flips back to true.
Cut the avatar off mid-sentence. It returns to listening.
A manual interrupt, aimed at a "stop talking" button in your own UI. Cuts the avatar off and goes back to listening.
Prefer controls.stopSpeaking: true if you are using the built-in bar — it
renders the same button and shows it only while the avatar speaks.
Muting the mic drops outbound audio, so the server genuinely hears silence — it is not a UI-only flag. Muting the speaker silences playback while lip-sync keeps animating, so the avatar does not appear frozen.
Set turnTaking: { mode: "push-to-talk" } on the config, then wire the press
and release. Pressing cuts the avatar off if it was speaking, which is what
makes barge-in work.
Handle onPointerCancel and onPointerLeave, not just onPointerUp. A
pointer that leaves the button or gets cancelled by the OS otherwise leaves the
turn open forever.
By default the SDK also accepts the spacebar. Set turnTaking.spacebar: false
if your page binds it too.
These are undefined outside their mode, so always use optional chaining.
tts mode. The avatar speaks the string with full lip-sync.
Text over 5000 characters is rejected with a non-fatal INVALID_INPUT.
audio mode. Feed audio from any source and the avatar lip-syncs to it.
See Limits for the required PCM format.
player mode. Play a pre-rendered AvatarSpeech job locally.
call mode, requires a live session. Tell the avatar what the user is doing
right now.
With no live session the context is dropped and a non-fatal NOT_CONNECTED
error is emitted. Empty or over-length context emits a non-fatal
INVALID_INPUT. Neither ends the session.
Rigs can advertise named gestures. Read what is available, then fire one.
availableActions comes from the loaded rig, so it is empty until the avatar
is ready and differs between characters. Never hard-code a gesture name —
render from the list.
A notice is not an error. It is the server ending the session deliberately — a plan limit, a demo cap, a test key expiring — and the avatar speaks the message before the session closes.
Unlike error.message, notice.message is written for your users — it is
the same text the avatar just said out loud.
health.concern is the single thing to render from; the per-service map is for
a debug panel.
You get this for free — the built-in status banner renders exactly this and is
on by default. Write your own only if you need it somewhere else on the page,
and turn the built-in one off with statusBanner: { enabled: false }.
For subscribing outside the component lifecycle, or grouping events in one
useEffect. For everything else prefer
useAvatarEvent, which cleans up for you.