Every knob and switch in one place — the complete AvatarConfig object, field by field.
AvatarConfig splits into two halves: session wiring (how this session runs)
at the top level, and the agent definition (what the avatar is) under
avatar. The same avatar can run hands-free in one app and push-to-talk in
another, which is why turn taking is not part of the avatar.
It is also a discriminated union — you must supply exactly one of apiKey,
getSessionToken, or deployId. Supplying more than one is a TypeScript error.
Set avatar.avatarId to "default" to use our public demo avatar while you
build. For production, publish your own avatar
and use its ID.
| Prop | Type | Default | Description |
|---|---|---|---|
getSessionTokenRequired | () => Promise<string> | No default | Callback returning a fresh, single-use session token. Invoked on every connect. Exactly one of getSessionToken, apiKey, or deployId is required. Recommended for production. |
deployIdRequired | string | No default | Public deployment ID (dep_…) — no backend needed. Domain-locked and budget-capped, so it is safe to ship to the browser. |
apiKeyRequired | string | No default | Test key (af_test_*) for local development only. Live keys (af_live_*) are rejected by this path — use getSessionToken in production. |
modeOptional | "call" | "tts" | "audio" | "call" | Operating mode. Changing this at runtime triggers a full session reset. |
turnTaking.modeOptional | "auto" | "push-to-talk" | "auto" | Who decides a turn is over: the server's endpointer, or the user holding a button. Call mode only. |
turnTaking.spacebarOptional | boolean | true | Let the user hold the spacebar as well as the button. Web only. Set false when your page binds space itself — the SDK swallows the key while connected. |
controls.enabledOptional | boolean | false | Show the built-in start / stop / mute bar. Hidden unless explicitly true. |
controls.stopSpeakingOptional | boolean | false | Add a "stop talking" button to the built-in bar, shown only while the avatar speaks. useAvatar().stopSpeaking() is always available for a custom one. |
perception.cameraOptional | boolean | false | Allow the avatar to see. Opt-in, and even then the camera opens just-in-time when the server asks — never on connect. See Camera perception. |
transcript.enabledOptional | boolean | false | Assemble a live transcript. Off means none is built at all. See Transcript & captions. |
transcript.captionsOptional | boolean | true | Render the built-in caption overlay. False keeps the data without the UI. |
transcript.positionOptional | CaptionPosition | "bottom-center" | Anchor for the caption overlay — six positions, corners plus top/bottom centre. |
transcript.maxEntriesOptional | number | 50 | Transcript lines retained. |
statusBanner.enabledOptional | boolean | true | Built-in connectivity banner, driven by live stream health. On by default; it only appears when something is wrong. |
statusBanner.positionOptional | StatusBannerPosition | "bottom-left" | Anchor corner. Corners only — no centre anchors. |
thinkingIndicator.enabledOptional | boolean | true | Animated dots shown only while a turn runs unusually slow. A liveness cue, not a warning. |
thinkingIndicator.positionOptional | CaptionPosition | "top-left" | Anchor. A top corner stays clear of custom controls at the bottom. |
connectTone.enabledOptional | boolean | false | Play a ringback tone while the session connects. Stops once the avatar is painted and the session is live. |
connectTone.srcOptional | string | No default | URL or data URI for your own tone. Omit for the built-in one. Web only — React Native ignores it. |
connectTone.loopOptional | boolean | true | Repeat the tone until the connect completes. |
connectTone.volumeOptional | number | 0.4 | 0–1. The default sits under the conversation, not over it. |
connectTone.fadeOutMsOptional | number | 350 | Fade-out on stop, in milliseconds. A hard cut clicks. |
debugOptional | boolean | false | Verbose console logging. Disable before shipping. |
| Prop | Type | Default | Description |
|---|---|---|---|
avatar.avatarIdRequired | string | No default | Which character to load. Use "default" for the public demo avatar, or publish your own and use its ID. |
avatar.systemPromptOptional | string | No default | Per-session context — who the end user is and why they are here. Call mode. Not the avatar's identity: set that on the platform. |
avatar.languagesOptional | "auto" | AvatarLanguage[] | No default | Languages the conversation may use. "auto" lets the server detect and switch mid-conversation; an array restricts it. Omitted means English. |
avatar.brainOptional | AvatarBrain | No default | Which model powers the conversation: { provider, model?, useOwnBrain? }. |
avatar.voiceSettingsOptional | AvatarVoiceSettings | No default | Voice provider, voice, and tuning. See below. |
avatar.greetingOptional | GreetingConfig | No default | An opening line spoken once the session goes live: { enabled, message?, language? }. |
avatar.layoutOptional | Record<string, string> | No default | Platform-agnostic rendering hints for the canvas, interpreted per platform. Usually left to what the avatar was published with. |
Three ways in. For production, always getSessionToken — your key never leaves
the backend and tokens expire in seconds.
The getSessionToken callback runs on every connect — initial and every
reconnect. Tokens are single-use, so mint a fresh one each call. See
Authentication for backend implementations, and
API keys for which credential belongs where.
mode is what kind of conversation this is; turnTaking is who ends a turn
inside it.
In "auto" the server's endpointer decides from the audio. In
"push-to-talk" the user holds a button — read isPushToTalk and drive it with
startTalking() / stopTalking() from useAvatar,
or let the built-in controls render the button for you.
While connected in push-to-talk, the SDK listens for the spacebar. If your page
already binds space, set spacebar: false or the two will fight.
provider is deliberately open-ended: the server validates it, so a newly
supported vendor works without an SDK release.
useOwnBrain is a switch, not a carrier — the key is resolved server-side from
your account and never passes through the SDK. See
Bring your own keys.
Which models are available depends on your plan, and some are BYOK-only. The Platform's Brain tab shows the live catalogue with availability; a model that is not offered there will be rejected at call time.
| Prop | Type | Default | Description |
|---|---|---|---|
providerOptional | "elevenlabs" | "inworld" | No default | Which speech engine voices the avatar. Choosing one needs no setup — it runs on your plan's included minutes with a default voice. |
voiceIdOptional | string | No default | A specific voice on that provider. |
useOwnVoiceOptional | boolean | unset — the avatar's binding decides | Route speech through your own account with that provider. Requires a saved provider key, and a plan that includes BYOK. Omit it to follow the avatar's binding; false vetoes that binding for this integration. Calls on your own voice key do not draw platform minutes. |
visimeMsOptional | number | 40 | Viseme grouping window. Mouth shapes closer together than this are merged into one. |
voiceSpeedOptional | number | No default | Passed through to the voice engine. |
voiceStabilityOptional | number | No default | Passed through to the voice engine. |
similarityBoostOptional | number | No default | Passed through to the voice engine. |
Check your TTS provider's own documentation for valid ranges of voiceSpeed,
voiceStability, and similarityBoost — the SDK passes them straight through.
An opening line the avatar speaks once the session goes live. You do not supply audio — give it text, or let it use the built-in line for a language.
Greeting languages: en, es, fr, de, hi, ru, pt, ja, it.
A greeting is speech, and browsers block speech that did not follow a user gesture. Start the session from a real click, or the avatar will greet an audience that cannot hear it.
Supported: en, es, fr, de, hi, ru, pt, ja, it, nl. Omitting
the field means English. Note the greeting list is the same set minus Dutch.
The "waiting for someone to pick up" ringback, for products where connecting should feel like placing a call.
It stops once the avatar is painted and the session is live — not when either one lands first, so it never cuts out into silence while the user waits. There is also a hard ceiling of 15 seconds, so a wedged load cannot leave the tone droning indefinitely.
When a greeting is enabled too, the avatar waits 500 ms after the session goes live before speaking, so the ringback's fade can finish. Without the beat an instant greeting sounds clipped.
Voice, brain, language, and lip-sync settings can come from two places. They resolve in a fixed order:
| Priority | Source | Notes |
|---|---|---|
| 1 | The value in your SDK config | Always wins. |
| 2 | The value saved when the avatar was published | Used when the config omits it. |
| 3 | The system default | Used when neither is set. |
Voice fallback. If no valid voice is selected — at publish time or in code — the avatar falls back to the default voice for the selected provider, on both ElevenLabs and Inworld. An invalid voice ID does the same. The avatar always speaks.
Pass new values to the provider to update them live.
Changing auth (apiKey / getSessionToken / deployId) or mode triggers a
full session reset. Other fields update without one.
Memoise the config object. A new object literal on every render is a new
config every render. useMemo it, keyed on the values that actually change,
or you will restart the session continuously.