LiveKit docs › Models › Virtual avatar › Overview

---

# Virtual avatar models overview

> Guides for adding virtual avatars to your agents.

## Overview

Virtual avatars add lifelike video output for your voice AI agents. You can integrate a variety of providers to LiveKit Agents with just a few lines of code.

### Plugins

The following plugins are available. Choose a plugin from this list for a step-by-step guide:

| Provider | Python | Node.js |
| -------- | ------ | ------- |
| [Anam](https://docs.livekit.io/agents/models/avatar/plugins/anam.md) | ✓ | ✓ |
| [Avatario](https://docs.livekit.io/agents/models/avatar/plugins/avatario.md) | ✓ | — |
| [AvatarTalk](https://docs.livekit.io/agents/models/avatar/plugins/avatartalk.md) | ✓ | — |
| [Beyond Presence](https://docs.livekit.io/agents/models/avatar/plugins/bey.md) | ✓ | ✓ |
| [bitHuman](https://docs.livekit.io/agents/models/avatar/plugins/bithuman.md) | ✓ | — |
| [D-ID](https://docs.livekit.io/agents/models/avatar/plugins/did.md) | ✓ | — |
| [Keyframe](https://docs.livekit.io/agents/models/avatar/plugins/keyframe.md) | ✓ | — |
| [LemonSlice](https://docs.livekit.io/agents/models/avatar/plugins/lemonslice.md) | ✓ | ✓ |
| [LiveAvatar](https://docs.livekit.io/agents/models/avatar/plugins/liveavatar.md) | ✓ | — |
| [Runway](https://docs.livekit.io/agents/models/avatar/plugins/runway.md) | ✓ | ✓ |
| [Simli](https://docs.livekit.io/agents/models/avatar/plugins/simli.md) | ✓ | — |
| [Tavus](https://docs.livekit.io/agents/models/avatar/plugins/tavus.md) | ✓ | ✓ |
| [TruGen](https://docs.livekit.io/agents/models/avatar/plugins/trugen.md) | ✓ | ✓ |
| [Hedra (deprecated)](https://docs.livekit.io/agents/models/avatar/plugins/hedra.md) | ✓ | ✓ |

Have another provider in mind? LiveKit is open source and welcomes [new plugin contributions](https://docs.livekit.io/agents/models.md#contribute).

## Usage

The virtual avatar plugins work with the `AgentSession` class automatically. The plugin adds a separate participant, the avatar worker, to the room. The agent session sends its audio output to the avatar worker instead of to the room, which the avatar worker uses to publish synchronized audio + video tracks to the room and the end user.

To add a virtual avatar:

1. Install the selected plugin and API keys
2. Create an `AgentSession`, as in the [voice AI quickstart](https://docs.livekit.io/agents/start/voice-ai.md)
3. Create an `AvatarSession` and configure it as necessary
4. Start the avatar session, passing in the `AgentSession` instance
5. Start the `AgentSession` with audio output disabled (the audio is sent to the avatar session instead)

### Sample code

Here is an example using [Anam](https://docs.livekit.io/agents/models/avatar/plugins/anam.md):

```python
from livekit import agents
from livekit.agents import AgentServer, AgentSession
from livekit.plugins import anam

server = AgentServer()

@server.rtc_session(agent_name="my-agent")
async def my_agent(ctx: agents.JobContext):
   session = AgentSession(
      # ... stt, llm, tts, etc.
   )

   avatar = anam.AvatarSession(
      persona_config=anam.PersonaConfig(
         name="...",  # Name of the avatar to use.
         avatarId="...",  # ID of the avatar to use.
      ),
   )

   # Start the avatar and wait for it to join
   await avatar.start(session, room=ctx.room)

   # Start your agent session with the user
   await session.start(
      # ... room, agent, room_options, etc....
   )

```

## Avatar workers

To minimize latency, the avatar provider joins the LiveKit room directly as a secondary participant to publish synchronized audio and video to the room. In your frontend app, you must distinguish between the agent — your Python program running the `AgentSession` — and the avatar worker.

```mermaid
graph LR
User[User] --"User Audio"--> Agent[Agent]
Agent -."Audio Data".-> Avatar[Avatar Worker]
Avatar --"Agent Video"--> User
Avatar --"Agent Audio"--> User
```

You can identify an avatar worker as a participant of kind `agent` with the attribute `lk.publish_on_behalf`. Check for these values in your frontend code to associate the worker's audio and video tracks with the agent.

```typescript
const agent = room.remoteParticipants.find(
  p => p.kind === Kind.Agent && p.attributes['lk.publish_on_behalf'] === null
);
const avatarWorker = room.remoteParticipants.find(
  p => p.kind === Kind.Agent && p.attributes['lk.publish_on_behalf'] === agent.identity
);

```

In React apps, use the [useVoiceAssistant hook](https://docs.livekit.io/reference/components/react/hook/usevoiceassistant.md) to get the correct audio and video tracks automatically:

```typescript
const {
  agent, // The agent participant
  audioTrack, // the worker's audio track
  videoTrack, // the worker's video track
} = useVoiceAssistant();

```

### Custom avatar workers

Available in:
- [ ] Node.js
- [x] Python

> ℹ️ **Note**
> 
> This section is for developers building their own remote avatar workers, typically using the [`AvatarRunner`](https://docs.livekit.io/reference/python/livekit/agents/voice/avatar.md#livekit.agents.voice.avatar.AvatarRunner) helper. To use one of the supported avatar providers instead, see [Plugins](#plugins).

A custom avatar worker can call the `lk.playback_started` RPC to signal the agent session that audio playback has actually started on the worker.

Opt in by setting `wait_playback_start=True` on [`DataStreamAudioOutput`](https://docs.livekit.io/reference/python/livekit/agents/voice/avatar.md#livekit.agents.voice.avatar.DataStreamAudioOutput):

- `False` (default): `on_playback_started` fires on the first captured frame. Timing is approximate.
- `True`: `on_playback_started` is deferred until the worker sends `lk.playback_started`. Timing reflects when audio actually started playing.

```python
from livekit.agents.voice.avatar import DataStreamAudioOutput

AVATAR_IDENTITY = "avatar_worker"

session.output.audio = DataStreamAudioOutput(
    ctx.room,
    destination_identity=AVATAR_IDENTITY,
    wait_playback_start=True,
)

```

If your worker uses `AvatarRunner`, the RPC is sent automatically the first time it forwards an audio frame. For workers that don't use `AvatarRunner`, call `notify_playback_started()` on your `DataStreamAudioReceiver` instance when playback begins.

For a complete custom-worker example, see the [`audio_wave` avatar example](https://github.com/livekit/agents/tree/main/examples/avatar_agents/audio_wave) on GitHub.

## Frontend starter apps

The following [frontend starter apps](https://docs.livekit.io/agents/start/frontend.md#starter-apps) include out-of-the-box support for virtual avatars.

- **[SwiftUI Voice Agent](https://docs.livekit.io/frontends/start/starter-apps/swiftui.md)**: A native iOS, macOS, and visionOS voice AI assistant built in SwiftUI.

- **[Next.js Voice Agent](https://docs.livekit.io/frontends/start/starter-apps/react.md)**: A web voice AI assistant built with React and Next.js.

- **[Flutter Voice Agent](https://docs.livekit.io/frontends/start/starter-apps/flutter.md)**: A cross-platform voice AI assistant app built with Flutter.

- **[React Native Voice Agent](https://docs.livekit.io/frontends/start/starter-apps/react-native.md)**: A native voice AI assistant app built with React Native and Expo.

- **[Android Voice Agent](https://docs.livekit.io/frontends/start/starter-apps/android.md)**: A native Android voice AI assistant app built with Kotlin and Jetpack Compose.

- **[Agent Console](https://docs.livekit.io/agents/start/console.md)**: A virtual workbench to test your multimodal AI agent.

## Additional resources

- **[Web and mobile frontends](https://docs.livekit.io/agents/start/frontend.md)**: Guide to adding web or mobile frontends to your agent.

- **[Vision](https://docs.livekit.io/agents/multimodality/vision.md)**: Give your agent the ability to see you, too.

---

This document was rendered at 2026-06-07T11:33:40.628Z.
For the latest version of this document, see [https://docs.livekit.io/agents/models/avatar.md](https://docs.livekit.io/agents/models/avatar.md).

To explore all LiveKit documentation, see [llms.txt](https://docs.livekit.io/llms.txt).