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

# Serverside Setup With LiveKit

> Server-side setup for LiveKit + SpatialReal avatar

This guide covers how to send avatar audio and animation to a LiveKit room from your backend. Choose the path that matches how you build your voice agent.

***

## 1. Using the LiveKit Agents Framework

If you already use [LiveKit Agents](https://docs.livekit.io/agents/) to build your voice agent, the simplest option is [livekit-plugins-spatialreal](https://github.com/spatialwalk/livekit-plugins-spatialreal). The plugin hooks into your agent pipeline, sends TTS audio to SpatialReal, and publishes the lip-synced avatar stream into your LiveKit room—so you don’t manage the Server SDK or egress config yourself.

For a working end-to-end reference, see [AvatarKit Voice Agent Demo](https://github.com/spatialwalk/avatarkit-voice-agent-demo/tree/main/livekit-cascade-voice-agent).

### How it works

1. Your agent runs as usual (VAD, STT, LLM, TTS or Realtime), your current AgentSession setup.
2. The plugin intercepts TTS audio from the agent and sends it to SpatialReal.
3. SpatialReal generates the avatar stream and publishes it to the same LiveKit room.
4. Your client join the room and use the SpatialReal RTC client to render the avatar.

Interruption and conversation state are handled inside the plugin.

### Python: livekit-plugins-spatialreal

**Install**

```bash theme={null}
pip install livekit-plugins-spatialreal
```

**Configure**

| Variable                       | Required | Description               |
| ------------------------------ | -------- | ------------------------- |
| `SPATIALREAL_API_KEY`          | Yes      | Your SpatialReal API key  |
| `SPATIALREAL_APP_ID`           | Yes      | Your SpatialReal app ID   |
| `SPATIALREAL_AVATAR_ID`        | Yes      | Avatar to use             |
| `SPATIALREAL_CONSOLE_ENDPOINT` | No       | Override console endpoint |
| `SPATIALREAL_INGRESS_ENDPOINT` | No       | Override ingress endpoint |
| `LIVEKIT_URL`                  | Yes      | Your LiveKit server URL   |
| `LIVEKIT_API_KEY`              | Yes      | LiveKit API key           |
| `LIVEKIT_API_SECRET`           | Yes      | LiveKit API secret        |

**Use in your agent**

Create an `AvatarSession` and start it with your agent session and room. The plugin will attach to the pipeline and publish the avatar to the room.

```python theme={null}
from livekit.agents import Agent, AgentSession, JobContext, cli, WorkerOptions
from livekit.plugins import spatialreal

async def entrypoint(ctx: JobContext):
    await ctx.connect()

    session = AgentSession(vad=vad, stt=stt, llm=llm, tts=tts)
    avatar = spatialreal.AvatarSession()
    await avatar.start(session, room=ctx.room)

    await session.start(agent=YourAgent(), room=ctx.room)

if __name__ == "__main__":
    cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
```

Full API and options: **[livekit-plugins-spatialreal](https://github.com/spatialwalk/livekit-plugins-spatialreal)** (PyPI: [livekit-plugins-spatialreal](https://pypi.org/project/livekit-plugins-spatialreal/)).

### JavaScript plugin (coming soon)

JavaScript/TypeScript plugin for the LiveKit Agents framework will be available soon.

***

## 2. Using the Server SDK with LiveKit Egress

If you are **not** using LiveKit Agents (e.g. custom voice agent server), you can still send avatar output to a LiveKit room by using the **SpatialReal AvatarKit Server SDK** with **LiveKit egress** enabled.

You can also use the [AvatarKit Voice Agent Demo](https://github.com/spatialwalk/avatarkit-voice-agent-demo/tree/main/livekit-cascade-voice-agent) as a concrete reference for wiring a LiveKit-based voice agent.

In this setup:

* Your server sends audio to the avatar service and passes **LiveKit egress config** (room URL, credentials, room name, publisher id).
* The avatar service streams **audio + animation** directly into the LiveKit room (no need for your server to relay that data).
* Clients join the room and use [@spatialwalk/avatarkit-rtc](/guide/rtc-livekit-client) to render the avatar.

You keep full control over when and how you send audio (and optional interrupt signals; see below), while transport and sync are handled by the service and the RTC client.

### Configuration

| Field          | Description                                                |
| -------------- | ---------------------------------------------------------- |
| `url`          | LiveKit server URL (e.g., `wss://your-livekit-server.com`) |
| `api_key`      | LiveKit API key                                            |
| `api_secret`   | LiveKit API secret                                         |
| `room_name`    | LiveKit room name to publish to                            |
| `publisher_id` | Publisher identity in the room                             |

### Golang Example

```go theme={null}
session := avatarsdkgo.NewAvatarSession(
	avatarsdkgo.WithAPIKey("your-api-key"),
	avatarsdkgo.WithAppID("your-app-id"),
	avatarsdkgo.WithAvatarID("your-avatar-id"),
	avatarsdkgo.WithConsoleEndpointURL("https://console.us-west.spatialwalk.cloud/v1/console"),
	avatarsdkgo.WithIngressEndpointURL("wss://api.us-west.spatialwalk.cloud/v2/driveningress"),
	avatarsdkgo.WithExpireAt(time.Now().Add(5 * time.Minute)),
	avatarsdkgo.WithLiveKitEgress(&avatarsdkgo.LiveKitEgressConfig{
		URL:         "wss://your-livekit-server.com",
		APIKey:      "livekit-api-key",
		APISecret:   "livekit-api-secret",
		RoomName:    "your-room-name",
		PublisherID: "avatar-publisher",
	}),
	avatarsdkgo.WithOnError(func(err error) {
		// handle error
	}),
	avatarsdkgo.WithOnClose(func() {
		// handle close
	}),
)
```

### Python Example

```python theme={null}
from avatarkit import new_avatar_session, LiveKitEgressConfig

session = new_avatar_session(
    api_key="your-api-key",
    app_id="your-app-id",
    avatar_id="your-avatar-id",
    expire_at=datetime.now(timezone.utc) + timedelta(minutes=5),
    console_endpoint_url="https://console.us-west.spatialwalk.cloud/v1/console",
    ingress_endpoint_url="wss://api.us-west.spatialwalk.cloud/v2/driveningress",
    livekit_egress=LiveKitEgressConfig(
        url="wss://your-livekit-server.com",
        api_key="livekit-api-key",
        api_secret="livekit-api-secret",
        room_name="your-room-name",
        publisher_id="avatar-publisher",
    ),
    on_error=lambda err: print(f"Error: {err}"),
    on_close=lambda: print("Session closed"),
)
```

After the session is created with LiveKit egress, send audio as in normal Server SDK usage; the service will publish to the configured room automatically.

### Important Notes

When LiveKit egress is enabled:

* The `TransportFrames` / `transport_frames` callback will **not** be invoked
* Audio and animation data are published directly to the specified LiveKit room
* Your client must use the **@spatialwalk/avatarkit-rtc** package to render the avatar (standard video players won't work). See [LiveKit Client Guide](/guide/rtc-livekit-client) for client setup.

### Interrupt

You can interrupt the avatar (e.g. when the user asks a new question). The interrupt uses the most recent request ID, even after `end=true` was sent.

**Golang**

```go theme={null}
// Send audio
requestID, err := session.SendAudio(audioData, true)

// Later, interrupt if needed
interruptedID, err := session.Interrupt()
```

**Python**

```python theme={null}
# Send audio
request_id = await session.send_audio(audio_data, end=True)

# Later, interrupt if needed
interrupted_id = await session.interrupt()
```

***

## Summary

| Approach                        | Best for                                                           | Where to go                                                                                                      |
| ------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| **LiveKit Agents + Plugin**     | Python (or future JS) agents using the LiveKit Agents framework    | [livekit-plugins-spatialreal](https://github.com/spatialwalk/livekit-plugins-spatialreal) (this page, section 1) |
| **Server SDK + LiveKit egress** | Custom backends, any language with a Server SDK (Go, Python, etc.) | This page, section 2                                                                                             |

For client-side setup (joining the room and rendering the avatar), see [LiveKit client guide](/guide/rtc-livekit-client).
