LiveKit Agents Plugin for SpatialReal Avatar
This plugin provides integration with SpatialReal's avatar service for lip-synced avatar rendering in LiveKit voice agents.
Installation
pip install livekit-plugins-spatialreal
Versioning
Starting with 1.7.1, the plugin's major and minor version track the livekit-agents
release it was validated against (e.g. plugin 1.8.x targets livekit-agents 1.8.x). The
patch number is the plugin's own and may advance independently.
The current release, 1.8.6, is validated against livekit-agents 1.8.6.
Or install from source:
pip install -e .
Configuration
Set the following environment variables:
# Required
SPATIALREAL_API_KEY=your-api-key
SPATIALREAL_APP_ID=your-app-id
SPATIALREAL_AVATAR_ID=your-avatar-id
# Optional
# Named SpatialReal deployment; the SDK resolves its endpoints. Defaults to the public one.
SPATIALREAL_ENVIRONMENT=
# Explicit endpoints, for a deployment SpatialReal gives you addresses for. They win over
# SPATIALREAL_ENVIRONMENT.
SPATIALREAL_CONSOLE_ENDPOINT=
SPATIALREAL_INGRESS_ENDPOINT=
# Max seconds of per-response audio retained for false-interruption resume (default 180, min 10)
SPATIALREAL_RESUME_BUFFER_MAX_SECONDS=
# TTL (seconds) of the LiveKit room-join token the egress worker uses; must outlive
# the whole session so mid-session reconnects don't hit an expired token (default 86400)
SPATIALREAL_LIVEKIT_TOKEN_TTL_SECONDS=
# LiveKit credentials
LIVEKIT_URL=
LIVEKIT_API_KEY=
LIVEKIT_API_SECRET=
Usage
from livekit.agents import Agent, AgentSession, JobContext, cli, WorkerOptions
from livekit.plugins import spatialreal
class VoiceAssistant(Agent):
def __init__(self):
super().__init__(instructions="You are a helpful voice assistant.")
async def entrypoint(ctx: JobContext):
await ctx.connect()
# Configure your pipeline components (VAD, STT, LLM, TTS)
session = AgentSession(
vad=vad,
stt=stt,
llm=llm,
tts=tts,
)
# Initialize and start the avatar session
avatar = spatialreal.AvatarSession()
await avatar.start(session, room=ctx.room)
# Start the agent session
await session.start(
agent=VoiceAssistant(),
room=ctx.room,
)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
For production agents, catch SpatialRealException so you can decide whether to fail the job or continue without avatar output:
try:
await avatar.start(session, room=ctx.room)
except spatialreal.SpatialRealException as err:
logger.error("Avatar startup failed: %s", err)
raise
API Reference
AvatarSession
Main class for integrating SpatialReal avatars with LiveKit agents.
Constructor Parameters
| Parameter | Type | Description |
|---|---|---|
api_key |
str |
SpatialReal API key (or set SPATIALREAL_API_KEY) |
app_id |
str |
SpatialReal application ID (or set SPATIALREAL_APP_ID) |
avatar_id |
str |
Avatar ID to use (or set SPATIALREAL_AVATAR_ID) |
environment |
str |
Named SpatialReal deployment whose endpoints the SDK resolves (or set SPATIALREAL_ENVIRONMENT); defaults to the public deployment |
console_endpoint_url |
str |
Explicit console endpoint, for a private deployment (or set SPATIALREAL_CONSOLE_ENDPOINT) |
ingress_endpoint_url |
str |
Explicit ingress endpoint, for a private deployment (or set SPATIALREAL_INGRESS_ENDPOINT) |
avatar_participant_identity |
str |
LiveKit identity for avatar participant |
avatar_participant_name |
str |
LiveKit display name for avatar participant |
idle_timeout_seconds |
int |
LiveKit egress idle timeout in seconds (0 uses server defaults) |
sample_rate |
int | None |
Optional avatar audio sample rate override |
livekit_token_ttl_seconds |
int |
TTL of the LiveKit room-join token used by the egress worker; must outlive the whole session (or SPATIALREAL_LIVEKIT_TOKEN_TTL_SECONDS; default 86400) |
Methods
start(agent_session, room, *, livekit_url, livekit_api_key, livekit_api_secret): Start the avatar session and hook into the agent's audio output. RaisesSpatialRealExceptionwith actionable context if startup fails.aclose(): Clean up avatar session resources.
When starting, the plugin automatically sets lk.publish_on_behalf to the
agent participant identity for avatar worker association in LiveKit frontends.
Events
playback_started— emitted with anAvatarPlaybackStartedEventwhen audible avatar playback is first observed for a request.
@avatar.on("playback_started")
def _on_playback_started(ev: spatialreal.AvatarPlaybackStartedEvent):
logger.info("avatar playing request %s (via %s)", ev.request_id, ev.source)
AvatarPlaybackStartedEvent
| Field | Type | Description |
|---|---|---|
request_id |
str |
SpatialReal request the playback belongs to |
source |
str |
Signal that observed the start (e.g. livekit_avatar_audio_track) |
observed_at |
float |
Unix timestamp of the observation |
SpatialRealException
Exception raised for SpatialReal-related errors.
How It Works
- The plugin intercepts TTS audio output from the agent session
- Audio frames are forwarded to SpatialReal's avatar service
- SpatialReal generates lip-synced video and audio
- The avatar joins the LiveKit room and publishes the synchronized streams
Interruptions and false-interruption recovery
LiveKit Agents owns turn-taking and interruption decisions; the plugin never adds its own VAD
or interruption policy. The audio output the plugin installs advertises pause support, so the
framework's resume_false_interruption behaviour (on by default) works with the avatar:
- When the framework detects a possible interruption it calls
pause(). The plugin stops the current SpatialReal request and retains the unplayed PCM tail locally. - If the framework later rejects the interruption (a laugh, a backchannel, a cough), it calls
resume(). The plugin re-sends only the estimated unplayed remainder as a new request. - If the interruption is confirmed,
clear_buffer()discards the retained audio.
The retained tail is bounded by SPATIALREAL_RESUME_BUFFER_MAX_SECONDS.
License
Apache-2.0
Metadata
Release files for livekit-plugins-spatialreal 1.8.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| livekit_plugins_spatialreal-1.8.6.tar.gz | 28.3 kB | With provenance | Details for livekit_plugins_spatialreal-1.8.6.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| livekit_plugins_spatialreal-1.8.6-py3-none-any.whl | Python 3 | none | any | Details for livekit_plugins_spatialreal-1.8.6-py3-none-any.whl |
Total release size: 57.4 kB
Release files / livekit_plugins_spatialreal-1.8.6.tar.gz
| Download URL | livekit_plugins_spatialreal-1.8.6.tar.gz |
|---|---|
| Size | 28.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4a3634f5093ed876d5cb463863f5cd85f577c8f7c02bc83ba034aa5b68a64e70
|
|
BLAKE2b-256 checksum How to use checksums |
3697d5fee411555e4d911f3c8fc58f60aef441155e6c85e3705b50414677bfc7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / livekit_plugins_spatialreal-1.8.6-py3-none-any.whl
| Download URL | livekit_plugins_spatialreal-1.8.6-py3-none-any.whl |
|---|---|
| Size | 29.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9e1a4540273f5ed37b75026df9420663282ab648a83fe198c9aeea07ee7f042d
|
|
BLAKE2b-256 checksum How to use checksums |
adeb4e33963d915fa214199a072cc37d0d7494777e5a4acf021e664ea63ff2ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logSecurity for livekit-plugins-spatialreal 1.8.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for livekit_plugins_spatialreal-1.8.6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.