Know exactly what the avatar is doing at every moment — and build UI that responds to it.
The SDK tracks two things separately, and keeping them apart is most of what there is to know:
isIdle → isConnecting → isConnectedisLoading → isReady, or isFailedThey move independently. A previously-loaded avatar appears on screen before any call starts, and a call that drops leaves the avatar right where it was. So don't read one from the other: isIdle doesn't mean there's no avatar, and isReady doesn't mean you're in a call.
The two rows advance on their own clocks. Ending a call returns the top row to IDLE and leaves the bottom row untouched.
| Prop | Type | Default | Description |
|---|---|---|---|
IDLEOptional | isIdle = true | No default | No call. start() is available — including while the avatar is still loading, because start() waits the load out for you. |
CONNECTINGOptional | isConnecting = true | No default | start() is in flight: fetching a token, resolving the avatar, opening the connection, waiting for the server. True for the whole window from the tap to the call going live. |
CONNECTEDOptional | isConnected = true | No default | The call is live. The turn states below only apply from here. |
| Prop | Type | Default | Description |
|---|---|---|---|
LOADINGOptional | isLoading = true | No default | The avatar is coming up — being resolved, or resolved and still rendering. |
READYOptional | isReady = true | No default | The avatar is on screen and animating. |
FAILEDOptional | isFailed = true | No default | The avatar could not be loaded, so there is nothing on screen. start() tries again. |
These only mean anything while isConnected. Ending a call clears them all.
| Prop | Type | Default | Description |
|---|---|---|---|
GREETINGOptional | isSpeaking = true | No default | Speaking the opening line, when avatar.greeting.enabled is set. It starts ~500ms after the session goes live, so the connect tone's fade can finish first. |
LISTENINGOptional | isListening = true | No default | Waiting for user voice input. Call mode only. |
THINKINGOptional | isThinking = true | No default | The avatar is working out its reply, between listening and speaking. |
SPEAKINGOptional | isSpeaking = true | No default | Avatar is talking with real-time lip-sync animation. |
INTERRUPTEDOptional | — | No default | Speech was cut short by interrupt(). Returns to LISTENING. |
The cleanest split is to let each axis drive the thing it's actually about. <Avatar> already handles its own loading and failure states, so your controls only need the call:
That button is correct from the first render. It says "Start call" while the avatar is still loading — and it works, because start() waits for the load.
If you do want one status line covering both, answer the avatar first, since there's no point reporting on a call to an avatar that isn't there:
Use for rendering UI that reflects the current state. React re-renders when state changes.
// Conditional rendering
const { isSpeaking } = useAvatar();
return isSpeaking ? <Indicator /> : null;Use for side effects on state transitions — analytics, logging, auto-reconnect logic.
// Side effects
useAvatarEvent("speaking", () => {
analytics.track("spoke");
});A good mental model: state is for rendering, events are for reacting. If you're rendering UI based on avatar status, use useAvatar. If you're triggering an action when the status changes, use useAvatarEvent.