<!-- AvatarFactory Docs · https://avatarfactory.in/docs/sdk/react/avatar-provider · Full map: https://avatarfactory.in/llms.txt -->

# AvatarProvider

Wrap your app once. It connects to the avatar, holds the session, and shares it with every component inside.

`AvatarProvider` is where you connect and configure. Give it a `config` object —
how to authenticate, which avatar to load, and how the session should run — and
it makes the avatar available to `` and the `useAvatar` hook anywhere
below it.

## Basic usage

```tsx
"use client";
import { AvatarProvider } from "@avatarfactory/react";
import "@avatarfactory/react/styles.css";

const config = {
  getSessionToken: async () => {
    const res = await fetch("/api/avatar-token");
    const { sessionToken } = await res.json();
    return sessionToken;
  },
  mode: "call",
  avatar: { avatarId: "default" },
};

export default function RootLayout({ children }) {
  return <AvatarProvider config={config}>{children}</AvatarProvider>;
}
```

> **Define `config` outside the component, or memoise it.** A fresh object
>   literal on every render is a fresh config on every render, and the provider
>   will keep restarting the session. Use `useMemo` when any part of it is dynamic.

## Authentication

Provide **exactly one** of these three. Supplying more than one is a TypeScript
error.

| Method | Runs where | Use it for |
| --- | --- | --- |
| getSessionToken | Your backend mints | Production. Your key never leaves your server. |
| deployId | Browser, public | Framer, landing pages, demos — anywhere with no backend. |
| apiKey | Browser, dev only | Local development, with a test key. Live keys are rejected. |

### getSessionToken (recommended)

A session token is a short-lived credential good for a single connection. You
give the SDK a **function**, not a token string, so it can fetch a fresh one on
every connect — the first time and on every reconnect.

```tsx
<AvatarProvider
  config={{
    getSessionToken: async () => {
      const res = await fetch("/api/avatar-token");
      const { sessionToken } = await res.json();
      return sessionToken;
    },
    avatar: { avatarId: "default" },
  }}
>
  ...
</AvatarProvider>
```

**Contract:**

- Must return `Promise` resolving to a non-empty token.
- Takes no arguments — capture context in a closure.
- If it rejects or resolves empty, the SDK emits `SESSION_TOKEN_FETCH_FAILED`
  and aborts before any WebSocket opens.
- Tokens are never cached by the SDK; the callback runs on every connect.

Your backend exchanges your **live key** for a token. See
[Authentication](/docs/authentication) for cURL, Node, Next.js, and Python
implementations.

> Keep your live key in a **server-only** environment variable — no
>   `NEXT_PUBLIC_` prefix or equivalent. Anything prefixed for client exposure is
>   compiled into your bundle.

### deployId (public, no backend)

A deployment ID (`dep_…`) is a public credential scoped to one avatar in one
mode, locked to the domains you authorize and capped by a monthly minute budget.

```tsx
<AvatarProvider
  config={{
    deployId: "dep_...",
    avatar: { avatarId: "your-avatar-id" },
  }}
>
  ...
</AvatarProvider>
```

Create one in **Platform → open an avatar → Deploy → Framer → New deployment**
(paid plans only). The same ID powers the
[Framer component](/docs/sdk/framer/overview).

> A `deployId` is safe to ship to the browser. Unlike an API key it cannot be
>   repointed at another avatar, cannot work on a domain you did not authorize, and
>   cannot spend beyond its budget.

### apiKey (development only)

```tsx
<AvatarProvider
  config={{
    apiKey: process.env.NEXT_PUBLIC_AF_TEST_KEY, // af_test_* only
    avatar: { avatarId: "default" },
  }}
>
  ...
</AvatarProvider>
```

> This path accepts **test keys only**. Live keys (`af_live_*`) are rejected by
>   the server, and there is no flag to override that. See
>   [API keys](/docs/platform/api-keys).

## Config reference

`AvatarProvider` takes a single `config` prop of type `AvatarConfig`. Below is
the shape; every field, type, and default is in the
**[Configuration Reference](/docs/sdk/react/configuration)**.

```tsx
const config = {
  // Exactly one of these three
  getSessionToken: async () => fetchSessionToken(),

  // --- Session wiring: how this session runs ---
  mode: "call",                                  // default "call"
  turnTaking: { mode: "auto", spacebar: true },
  controls: { enabled: true, stopSpeaking: false },
  perception: { camera: false },
  transcript: { enabled: false, captions: true, position: "bottom-center" },
  statusBanner: { enabled: true, position: "bottom-left" },
  thinkingIndicator: { enabled: true, position: "top-left" },
  connectTone: { enabled: false, volume: 0.4 },
  debug: false,

  // --- Agent definition: what the avatar is ---
  avatar: {
    avatarId: "default",
    systemPrompt: "Returning customer, on the Growth plan since March.",
    languages: "auto",
    brain: { provider: "openai", model: "gpt-4.1-mini", useOwnBrain: false },
    voiceSettings: { provider: "elevenlabs", voiceId: "…", useOwnVoice: false },
    greeting: { enabled: true, message: "Hi! What are you planning?", language: "en" },
  },
};
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `config` **(required)** | `AvatarConfig` | — | The full configuration object. See the Configuration Reference for every field. |
| `children` **(required)** | `React.ReactNode` | — | Your app. , useAvatar(), and useAvatarEvent() work anywhere below. |

## The four things most people set first

### mode

`call` for two-way voice, `tts` to speak text you send, `audio` to lip-sync
audio you supply. See
[Modes](/docs/sdk/react/modes).

### controls

The SDK ships a start / stop / mute bar for `call` mode. It is **off by
default** — opt in, or build your own with
[`useAvatar`](/docs/sdk/react/use-avatar).

```tsx
controls: { enabled: true, stopSpeaking: true }
```

`stopSpeaking` adds an interrupt button that appears only while the avatar is
talking.

### avatar.systemPrompt

Context for *this* session — who your user is and what they came for. It is sent
once when the session opens and applies to that conversation only.

```tsx
avatar: {
  avatarId: "default",
  systemPrompt:
    "You're speaking with a Pro-tier customer, subscribed since 2023. " +
    "They arrived from the billing page.",
},
```

Keep it short. Because it changes from session to session it cannot be cached the
way the avatar's own configuration is, and it is re-sent on every turn of the
call.

> This is not where an avatar's personality or reference material goes. Set those
>   on the avatar itself in the platform — they persist across every session, hold
>   far more text, and stay in effect when you leave `systemPrompt` unset.

### avatar.greeting

An opening line spoken once the session goes live. Give it text, or omit
`message` for the built-in line in the chosen language.

```tsx
avatar: {
  avatarId: "default",
  greeting: { enabled: true, message: "Hey! What can I help with?" },
},
```

> Greetings are text now — you do not supply audio. If you are migrating from an
>   older integration that passed a pre-rendered `greeting.job` at the top level,
>   move it to `avatar.greeting` and pass a `message` string instead.

## How avatar settings are resolved

Voice, brain, language, and lip-sync settings can come from two places:

1. **The SDK config** — always wins.
2. **What you saved when you published the avatar** — 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 chosen provider — on both
>   ElevenLabs and Inworld. An invalid voice ID does the same. The avatar always
>   speaks.

## Common pitfalls

> **Don't nest providers** unless you deliberately want two independent sessions
>   running at once. Each `AvatarProvider` opens its own connection.

> **Client components only.** `AvatarProvider`, `useAvatar`, and `useAvatarEvent`
>   run in the browser. Mark any file that uses them `"use client"`.

> **Changing auth (`getSessionToken` / `apiKey` / `deployId`) or `mode` at
>   runtime triggers a full session reset.** Other fields — `systemPrompt`, voice
>   settings, overlays — update without one.
