> ## 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.

# LiveKit

> Have the avatar join your LiveKit room as a participant, with its video and voice as tracks.

Already using LiveKit? The avatar can join your room instead of streaming to your page. It publishes a lip-synced video track and its voice, in sync. Your LiveKit client plays them, so you don't need `LiveAvatarView` or a `/avatar` route.

You mint a **publish-only** token for the avatar's participant. Your LiveKit API key and secret stay with you.

## Set it up

**1. Install**

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

**2. Mint a token and start the avatar**

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

// 1. A LiveKit token for the avatar's participant (publish only).
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, { identity: `avatar-${room}` });
at.addGrant({ room, roomJoin: true, canPublish: true, canSubscribe: false });

// 2. The avatar joins with a video track "avatar" and its voice track "avatar-audio".
const avatar = await LiveAvatar.start({
  apiKey: process.env.TALKING_AVATAR_API_KEY, // tav_…
  avatar: "ava4",
  sampleRate: 24000,                          // your TTS rate
  livekit: { url: LIVEKIT_URL, token: await at.toJwt() },
});

// 3. Your TTS audio as it streams. We publish the voice with the lips.
tts.on("audio", (pcm) => avatar.pushAudio(pcm));

// The user interrupts
const heardMs = await avatar.clear();

// The conversation is over: billing stops
avatar.close();
```

**3. Play the tracks**

In your room, the avatar is a participant with the identity you gave its token (`avatar-<room>` above). It publishes:

| Track | Name | Content |
| - | - | - |
| Video | `avatar` | The avatar, 832 × 468 at 25 fps |
| Audio | `avatar-audio` | Your agent's voice, in sync with the lips |

Render them with your existing LiveKit client, and stop playing your agent's original voice track, so it isn't heard twice.

## Options

```js theme={null}
livekit: {
  url: LIVEKIT_URL,           // your LiveKit server URL
  token: avatarToken,         // publish-only token for the avatar
  audioTrackName: "agent-voice", // rename the voice track (default "avatar-audio")
  publishAudio: true,         // default true; see below
}
```

### Playing the voice yourself

By default the avatar publishes the voice in sync with its lips (recommended). If you need to play the voice through your own track instead, set `publishAudio: false`, and pass `playAtMs` to each `pushAudio` call: the wall-clock time, in milliseconds since the epoch, when that audio will be heard, sent about 400 ms early. In this mode `clear()` resolves with `null`, because the avatar can't know how much was heard.

```js theme={null}
avatar.pushAudio(pcm, { playAtMs: Date.now() + 400 });
```

## Python agents

On LiveKit Agents for Python, use the [realtime avatar API](https://docs.talking-avatar.dev/api-reference/realtime/overview.md) directly. The [Python example](https://docs.talking-avatar.dev/api-reference/realtime/python.md#your-livekit-room) mints the avatar's token with `livekit-api` and starts it in your room.


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