* rtc: keep the participant egress guard across a duplicate identity eviction Room.RemoveParticipant clears hasPublished[identity], which is the guard that stops auto participant egress launching twice for the same identity. A duplicate identity eviction calls RemoveParticipant with the outgoing participant's own ID, so the "participant session has been replaced" early return does not apply and the guard is dropped even though the identity stays in the room. The replacement session then publishes, finds no guard and launches a second participant egress. The first one does not stop: the egress SDK resolves its source by identity, so it follows the new SID, re-subscribes to the republished tracks and keeps recording. Both jobs then write the same media until the participant leaves for good. Keep the guard when the close reason is ParticipantCloseReasonDuplicateIdentity. launchedTrackEgresses is left as is, since it is keyed per track ID and a replacement session republishes with new track IDs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * rtc: separate the participant egress launch guard from hasPublished Review feedback on the first commit: hasPublished gates the publisher agent dispatch as well as participant egress, so preserving it across a duplicate identity eviction left the replacement session without its publisher jobs. Track the participant egress launch in its own identity keyed map. hasPublished is cleared on every removal as before, so agent dispatch is untouched, and only the egress guard survives a duplicate identity eviction. The preserved guard is also tied to a successful handoff: StartSession releases it when the session that caused the eviction fails to join, so it cannot strand an identity that is no longer in the room. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * rtc: only release a preserved egress guard while the identity is unoccupied Sessions for one identity can race. A handoff fails with ErrAlreadyJoined exactly when another session has already joined under that identity, and that session now owns the preserved participant egress guard. Releasing it there let the winner start a second egress on its next publication, alongside the job still recording. Release the guard only while the room holds no participant for the identity. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * rtc: drop the failed handoff release of the egress guard Review feedback: the duplicate identity disconnect is filtered, so the running participant egress keeps recording whether or not the replacement session ever joins. Releasing the guard on a failed handoff only gives the next session for that identity a way to launch a second job against the same tracks. Remove ClearLaunchedParticipantEgress and its StartSession deferred call. The guard is now released solely by RemoveParticipant on a non-duplicate removal or a room close, which is where the identity genuinely leaves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
LiveKit: Realtime infrastructure for voice, video, and AI agents
LiveKit is an open source platform for building voice, video, and physical AI agents. This repository is the LiveKit server: a scalable, distributed WebRTC SFU that moves realtime audio, video, and data between people, devices, and AI models. The SDKs, agents frameworks, and companion services are linked in the table at the bottom of this page.
LiveKit's server is written in Go, using the awesome Pion WebRTC implementation.
Important
If you're building Voice AI, LiveKit Agents is the SDK for code-first realtime voice agents. STT, LLM, TTS, turn detection, expressive speech, keyterm accuracy, tool usage, and telephony all come bundled in the framework. It's available in both Python and Node.js.
# agent.py from livekit import agents from livekit.agents import Agent, AgentServer, AgentSession, STTContextOptions, TurnHandlingOptions, inference server = AgentServer() @server.rtc_session(agent_name="my-agent") async def my_agent(ctx: agents.JobContext): session = AgentSession( stt=inference.STT(model="deepgram/nova-3", language="multi"), llm=inference.LLM(model="google/gemma-4-31b-it"), tts=inference.TTS(model="inworld/inworld-tts-2", voice="Ashley"), turn_handling=TurnHandlingOptions(turn_detection=inference.TurnDetector()), stt_context_options=STTContextOptions(keyterms=["LiveKit", "Acme Corp"]), expressive=True, ) await session.start(room=ctx.room, agent=Agent(instructions="You are a helpful voice AI assistant.")) await session.generate_reply(instructions="Greet the user and offer your assistance.") if __name__ == "__main__": agents.cli.run_app(server)Models come from LiveKit Inference with no per-provider API keys, and LiveKit Cloud handles deployment and observability. Visit the docs for more info at docs.livekit.io/agents.
Used in production by
LiveKit carries billions of calls a year for companies including Salesforce, Nvidia, Oracle, SAP, Deutsche Telekom, Spotify, Tinder, Coursera, Headspace, Skydio, Retell, Decagon, Cresta, and HeyGen. Read how Assort Health, Playback, and Polymath Robotics use it, or see more customers.
Features
- Scalable, distributed WebRTC SFU (Selective Forwarding Unit)
- People, devices, and AI agents join the same room as participants, with agent dispatch to route agents in automatically or on demand
- Modern, full-featured SDKs for web, mobile, desktop, embedded, and server
- Built for production, supports JWT authentication
- Robust networking and connectivity, UDP/TCP/TURN
- Easy to deploy: single binary, Docker or Kubernetes
- Advanced features including:
- speaker detection
- simulcast
- selective subscription
- moderation APIs
- end-to-end encryption
- SVC codecs (VP9, AV1)
- data tracks for low-latency telemetry and teleoperation
- telephony over SIP
- webhooks
- distributed and multi-region
Documentation & Guides
Working with a coding agent? Give it the LiveKit Docs MCP server, or start with the coding agents guide.
Live Demos
- Talk to a voice agent built with LiveKit Agents
- LiveKit Meet (source)
- Spatial Audio (source)
- Livestreaming from OBS Studio (source)
Install
Tip
We recommend installing LiveKit CLI along with the server. It lets you access server APIs, create tokens, generate test traffic, and scaffold and deploy agents.
The following will install LiveKit's media server:
MacOS
brew install livekit
Linux
curl -sSL https://get.livekit.io | bash
Windows
Download the latest release here
Getting Started
Starting LiveKit
Start LiveKit in development mode by running livekit-server --dev. It'll use a placeholder API key/secret pair.
API Key: devkey
API Secret: secret
To customize your setup for production, refer to our deployment docs
Creating access token
A user connecting to a LiveKit room requires an access token. Access tokens (JWT) encode the user's identity and the room permissions they've been granted. You can generate a token with our CLI:
lk token create \
--api-key devkey --api-secret secret \
--join --room my-first-room --identity user1 \
--valid-for 24h
Test with example app
Head over to our example app and enter a generated token to connect to your LiveKit server.
Once connected, your video and audio are now being published to your new LiveKit instance!
Simulating a test publisher
lk room join \
--url ws://localhost:7880 \
--api-key devkey --api-secret secret \
--identity bot-user1 \
--publish-demo \
my-first-room
This command publishes a looped demo video to a room. Due to how the video clip was encoded (keyframes every 3s), there's a slight delay before the browser has sufficient data to begin rendering frames. This is an artifact of the simulation.
Adding an agent
Agents join rooms as participants, the same way a browser or a phone does. Follow the Voice AI quickstart to build one. An agent connects to a self-hosted server the same way it connects to LiveKit Cloud; when running without Cloud, use model plugins in place of LiveKit Inference.
Deployment
Use LiveKit Cloud
LiveKit Cloud is the fastest and most reliable way to run LiveKit. It runs in 19+ regions with 99.99% uptime and adds agent hosting, model inference, telephony, and observability on top of the server. The Build plan is free, with no credit card required.
Sign up for LiveKit Cloud.
Self-host
Read our deployment docs for more information. Official Docker images and Helm charts are available.
Building from source
Pre-requisites:
- Go 1.26+ is installed
- GOPATH/bin is in your PATH
Then run
git clone https://github.com/livekit/livekit
cd livekit
./bootstrap.sh
mage
Contributing
We welcome your contributions toward improving LiveKit! Please join us on Slack or in the Developer Community to discuss your ideas and/or PRs.
License
LiveKit server is licensed under Apache License v2.0.
| LiveKit Ecosystem | |
|---|---|
| Agents SDKs | Python · Node.js |
| LiveKit SDKs | Browser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++ |
| Starter Apps | Python Agent · TypeScript Agent · React App · SwiftUI App · Android App · Flutter App · React Native App · Web Embed |
| UI Components | React · Android Compose · SwiftUI · Flutter |
| Server APIs | Node.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community) · .NET (community) |
| Resources | Docs · Docs MCP Server · CLI · LiveKit Cloud |
| LiveKit Server OSS | LiveKit server · Egress · Ingress · SIP |
| Community | Developer Community · Slack · X · YouTube |