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

# Installation

Two packages, a handful of native peers, and one Expo plugin. Prebuild once and you're ready.

## Requirements

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `react-native` **(required)** | `>= 0.78` | — | Minimum supported React Native version. |
| `Expo SDK` **(required)** | `>= 50` | — | Needed for the audio module's Expo plugin. |
| `Development build` | `required` | — | The SDK includes native code, so it runs in a custom dev build — not Expo Go. |

> This SDK includes a **native module** for echo-cancelled mic streaming and PCM playback. It will **not** run in Expo Go — you must use a development build (`npx expo prebuild` + a custom dev client or a bare workflow).

## Authenticate to npm first

`@avatarfactory/react-native` and `@avatarfactory/expo-audio` are **private
packages**. Add a `.npmrc` at your project root with the token issued with your
plan:

```ini
@avatarfactory:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${AVATARFACTORY_NPM_TOKEN}
```

Keep the token in your environment rather than in the file, so the `.npmrc` stays
safe to commit. EAS builds need it too — set it as a secret. Full setup:
**[Get access](/docs/access)**.

## Install the packages

```bash
# npm
npm install @avatarfactory/react-native @avatarfactory/expo-audio

# yarn
yarn add @avatarfactory/react-native @avatarfactory/expo-audio

# pnpm
pnpm add @avatarfactory/react-native @avatarfactory/expo-audio
```

> **Install the latest — don't pin a version.** The SDK is pre-1.0 and these docs
>   track the current release, so a pinned version drifts out of sync with what is
>   documented here. Run `npm ls @avatarfactory/react-native` to see what you are on.

### Peer dependencies

```bash
npm install @rive-app/react-native @react-native-async-storage/async-storage \
  expo-camera expo-image-manipulator react react-native
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `@rive-app/react-native` **(required)** | `>= 0.4.0` | — | Rive native runtime — renders the avatar character and drives lip-sync. |
| `@react-native-async-storage/async-storage` **(required)** | `>= 1.0.0` | — | Backs the avatar asset cache so .riv files load instantly on repeat opens. |
| `expo-camera` **(required)** | `>= 16.0.0` | — | Camera access for the optional perception feature. A declared peer dependency, so install it even if you never enable the camera. |
| `expo-image-manipulator` **(required)** | `>= 13.0.0` | — | Downscales and encodes camera frames before they are sent. |
| `react` **(required)** | `>= 18` | — | Core React library. |
| `react-native` **(required)** | `>= 0.78` | — | React Native runtime. |

> `expo-camera` and `expo-image-manipulator` are peer dependencies whether or not
>   you use [camera perception](/docs/sdk/react/perception). Install them to keep
>   the dependency tree resolvable; the camera itself stays off until you opt in
>   with `perception: { camera: true }`.

## Add the Expo plugin

`@avatarfactory/expo-audio` ships a config plugin that wires up the native audio module and declares microphone permissions for you. Add it in your `app.json` / `app.config.js`:

```json
{
  "expo": {
    "plugins": ["@avatarfactory/expo-audio"]
  }
}
```

The plugin automatically adds:

- **iOS** — `NSMicrophoneUsageDescription` to `Info.plist`
- **Android** — `RECORD_AUDIO` and `MODIFY_AUDIO_SETTINGS` to `AndroidManifest.xml`

Then run prebuild to apply the native changes:

```bash
npx expo prebuild
```

> Rebuild your dev client (`npx expo run:ios` / `npx expo run:android`, or an EAS build) after adding the plugin. A JS-only reload won't pick up the new native code.

## Quick start

No stylesheet import is needed — React Native styles everything inline.

```tsx
import { Button, View } from "react-native";
import { AvatarProvider, Avatar, useAvatar } from "@avatarfactory/react-native";

const config = {
  getSessionToken: async () => {
    const res = await fetch("https://your-backend.com/api/avatar-token", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ avatarId: "default" }),
    });
    const { sessionToken } = await res.json();
    return sessionToken;
  },
  mode: "call" as const,
  avatar: { avatarId: "default" },
};

export default function App() {
  return (
    <AvatarProvider config={config}>
      <MyAvatar />
    </AvatarProvider>
  );
}

function MyAvatar() {
  const { isReady, start, stop } = useAvatar();

  return (
    <View style={{ flex: 1 }}>
      <Avatar style={{ width: 320, height: 320 }} />
      <Button title="Start" onPress={start} disabled={!isReady} />
      <Button title="Stop" onPress={stop} />
    </View>
  );
}
```

> Always give `` an explicit size via `style` (or wrap it in a sized parent). Its root view is `flex: 1`, so inside an unsized parent it can collapse to zero height and appear invisible. See [Styling](/docs/sdk/react-native/styling).

> On React Native, production uses `getSessionToken` — your backend mints a short-lived token. The `apiKey` method is allowed for local development but accepts test keys only (`af_test_*`); live keys must use `getSessionToken`. See [AvatarProvider → Authentication](/docs/sdk/react-native/avatar-provider#authentication) for the backend route handler.
