> ## Documentation Index
> Fetch the complete documentation index at: https://docs.talking-avatar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Stream your agent's voice to a realistic avatar and show it on your page.

This guide uses **direct mode**: Talking Avatar streams the avatar's video and your agent's voice to your page over WebRTC. Already using LiveKit? See [LiveKit](https://docs.talking-avatar.dev/realistic-avatars/livekit.md) instead.

## Before you start

* A Talking Avatar account. [Sign up](https://app.talking-avatar.dev/sign-up) to get \$1 of free credits.
* Node.js 22 or later on your server (or Node.js 18 or 20 with the [`ws`](https://www.npmjs.com/package/ws) package). Another language? Use the [realtime avatar API](https://docs.talking-avatar.dev/api-reference/realtime/overview.md) instead.
* A voice: any TTS or voice agent that gives you raw 16-bit PCM audio. See [Stream audio](https://docs.talking-avatar.dev/realistic-avatars/streaming-audio.md) for provider settings.

## Steps

**1. Create an API key**

In the dashboard, open **API keys** → **Create key**. Copy the key and set it on your server:

```bash .env theme={null}
TALKING_AVATAR_API_KEY=tav_…
```

**2. Install the SDK**

In your server and in your web app:

```bash theme={null}
npm install @interviewflowai/talking-avatar
```

**3. Pick an avatar**

Choose an avatar ID from [Avatars](https://docs.talking-avatar.dev/realistic-avatars/avatars.md), such as `ava4` (professional, office) or `ava6` (casual, home study). You can try each one live on the dashboard's **Avatars** page.

**4. Start the avatar and add one route**

```js server.js theme={null}
import express from "express";
import { LiveAvatar } from "@interviewflowai/talking-avatar/server";

// 1. Start the avatar: we stream its video and your agent's voice over WebRTC.
const avatar = await LiveAvatar.start({
  apiKey: process.env.TALKING_AVATAR_API_KEY, // tav_…
  avatar: "ava4",
  sampleRate: 24000,                          // your TTS audio's sample rate
});

// 2. One route for your page: the WebRTC offer, then the browser's answer.
const app = express().use(express.json());
app.post("/avatar", async (req, res) => {
  try { res.json(await avatar.handleView(req.body)); }
  catch (error) { res.status(503).json({ error: error.message }); }
});
app.listen(3000);

// 3. Your TTS audio as it streams (PCM16 mono: Int16Array, Buffer or base64).
tts.on("audio", (pcm) => avatar.pushAudio(pcm));

// The user interrupts: drop what wasn't heard yet.
const heardMs = await avatar.clear();

avatar.on("speechEnded", (playedMs) => {});
avatar.on("close", (code, reason) => {}); // 4002: out of credits
// avatar.close() when the conversation is over: billing stops.
```

`handleView` answers your page's WebRTC requests. One route serves any number of viewers, and your API key never reaches the browser.

**5. Show it on your page**

```html index.html theme={null}
<div id="avatar" style="width: 640px; aspect-ratio: 16 / 9"></div>
<button id="watch">Start</button>
```

```js page.js theme={null}
import { LiveAvatarView } from "@interviewflowai/talking-avatar/live";

// Plays the avatar's video and voice, fitted in the element, and reconnects by itself.
const view = new LiveAvatarView({
  container: document.getElementById("avatar"),
  endpoint: "/avatar",                       // the route on your server
  onStatus: (status) => console.log(status), // connecting, live, reconnecting…
});

// From a click, so the browser lets the voice play.
document.getElementById("watch").onclick = () => view.connect();
```

**6. Talk to it**

Click **Start**, then make your agent speak. The avatar plays the voice in sync with its lips.

> [!WARNING]
>
> **Play the voice once.** The avatar plays your agent's voice itself, in sync with its lips. Remove any other playback of the same audio (an `<audio>` element, a speaker stream, `track.attach()`), or users hear it twice.

## One avatar per conversation

Keep one `LiveAvatar` per conversation: start it when the conversation starts, and `close()` it when it ends, so billing stops. Running several conversations at once? Give each its own route, such as `/avatar/:conversationId`, that looks up that conversation's avatar.

```js theme={null}
const avatars = new Map(); // conversationId → LiveAvatar

app.post("/avatar/:id", async (req, res) => {
  const avatar = avatars.get(req.params.id);
  if (!avatar) return res.status(404).json({ error: "No such conversation" });
  try { res.json(await avatar.handleView(req.body)); }
  catch (error) { res.status(503).json({ error: error.message }); }
});
```

Protect the route with your app's existing authentication.

## Next steps

> **[Stream audio](https://docs.talking-avatar.dev/realistic-avatars/streaming-audio.md)**
>
> Audio formats and settings for OpenAI, ElevenLabs, Azure and Cartesia.

> **[Interruptions](https://docs.talking-avatar.dev/realistic-avatars/interruptions.md)**
>
> Barge-in, speech events and keeping your transcript accurate.

> **[Sessions and errors](https://docs.talking-avatar.dev/realistic-avatars/sessions.md)**
>
> Billing, limits and close codes.

> **[Production checklist](https://docs.talking-avatar.dev/realistic-avatars/production-checklist.md)**
>
> Before you go live.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.