LiveKit - Open source, distributed video/audio rooms over WebRTC


LiveKit - Open source, distributed video/audio rooms over WebRTC

LiveKit is an open source project that provides scalable, multi-user conferencing over WebRTC. It's designed to give you everything you need to build real time video/audio capabilities in your applications.


  • Horizontally scalable WebRTC Selective Forwarding Unit (SFU)
  • Modern, full-featured client SDKs for JS, iOS, Android
  • Built for production - JWT authentication and server APIs
  • Robust networking & connectivity, over UDP & TCP
  • Easy to deploy - pure Go & single binary
  • Advanced features - speaker detection, simulcasting, selective subscription, moderation APIs.

Documentation & Guides

Docs & Guides at:

Try it live

Head to our playground and give it a spin. Build a Zoom-like conferencing app in under 100 lines of code!

SDKs & Tools

Client SDKs:

Server SDKs:



From source


  • Go 1.15+ is installed
  • GOPATH/bin is in your PATH
  • protoc is installed and in PATH

Then run

git clone
cd livekit-server


LiveKit is published to Docker Hub under livekit/livekit-server


Creating API keys

LiveKit utilizes JWT based access tokens for authentication to all of its APIs. Because of this, the server needs a list of valid API keys and secrets to validate the provided tokens. For more, see Access Tokens guide.

Generate API key/secret pairs with:

./bin/livekit-server generate-keys


docker run --rm livekit/livekit-server generate-keys

Store the generate keys in a YAML file like:

APIwLeah7g4fuLYDYAJeaKsSE: 8nTlwISkb-63DPP7OH4e.nw.J44JjicvZDiz8J59EoQ+

Starting the server

In development mode, LiveKit has no external dependencies. You can start LiveKit by passing it the keys it should use in LIVEKIT_KEYS. LiveKit could also use a config file or config environment variable LIVEKIT_CONFIG

: " ./bin/livekit-server --dev ">
LIVEKIT_KEYS=": " ./bin/livekit-server --dev


: " \ livekit/livekit-server \ --dev \ --node-ip= ">
docker run --rm \
  -p 7880:7880 \
  -p 7881:7881 \
  -p 7882:7882/udp \
  -e LIVEKIT_KEYS=": " \
  livekit/livekit-server \
  --dev \

When running with docker, --node-ip needs to be set to your machine's local IP address.

The --dev flag turns on log verbosity to make it easier for local debugging/development

Creating a JWT token

To create a join token for clients, livekit-server provides a convenient subcommand to create a development token. This token has an expiration of a month, which is useful for development & testing, but not appropriate for production use.

./bin/livekit-server --key-file <path/to/keyfile> create-join-token --room "myroom" --identity "myidentity"

Sample client

To test your server, you can use our example web client (built with our React component)

Enter generated access token and you are connected to a room!

Deploying for production

LiveKit is deployable to any environment that supports docker, including Kubernetes and Amazon ECS.

See deployment docs at


We welcome your contributions to make LiveKit better! Please join us on Slack to discuss your ideas and/or submit PRs.


LiveKit server is licensed under Apache License v2.0.

  • High activity rooms cause `

    High activity rooms cause `"error": "channel is full"` errors


    We had a live call with over 90 people. Things were going fine early on, but then we noticed users weren't able to publish video/audio, and suddenly some users who did publish would come through as a black screen. The error we were seeing over and over in the server looks like this:

    Apr 2, 2021 @ 14:27:11.777 | <14>1 2021-04-02T18:27:10.858904Z - - - - - 	/workspace/pkg/routing/redisrouter.go:311 |  
    -- | -- | --
      |   | Apr 2, 2021 @ 14:27:11.777 | <14>1 2021-04-02T18:27:10.858898Z - - - - -*RedisRouter).redisWorker |  
      |   | Apr 2, 2021 @ 14:27:11.777 | <14>1 2021-04-02T18:27:10.859405Z - - - - - 2021-04-02T18:27:10.859Z	ERROR	routing/redisrouter.go:311	error processing signal message	{"error": "channel is full"} |  
      |   | Apr 2, 2021 @ 14:27:11.777 | <14>1 2021-04-02T18:27:10.859435Z - - - - -*RedisRouter).redisWorker |  
      |   | Apr 2, 2021 @ 14:27:11.777 | <14>1 2021-04-02T18:27:10.859444Z - - - - - 	/workspace/pkg/routing/redisrouter.go:311 |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.854218Z - - - - -*RedisRouter).redisWorker |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.855512Z - - - - -*RedisRouter).redisWorker |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.855518Z - - - - - 	/workspace/pkg/routing/redisrouter.go:311 |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.854223Z - - - - - 	/workspace/pkg/routing/redisrouter.go:311 |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.858236Z - - - - - 	/workspace/pkg/routing/redisrouter.go:311 |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.856528Z - - - - -*RedisRouter).redisWorker |  
      |   | Apr 2, 2021 @ 14:27:11.776 | <14>1 2021-04-02T18:27:10.858231Z - - - - -*RedisRouter).redisWorker

    It looks like the channel used for the socket is filling up and once that happens, the connected user doesn't receive any new events and can't publish any new events either

    opened by atbe 12
  • Lingering connections even after a client socket is disconnected

    Lingering connections even after a client socket is disconnected

    I'm not sure what to include for this when it comes to logs because I can't pinpoint this down to a specific error

    When there is a flood of new connections, some of the participants never get cleaned out when their socket disconnects

    I ran this command to see how many connections were open on the server:

    # cat /proc/net/tcp | wc -l

    Although one of the rooms I'm currently in reports 926 participants and the redis records for all the disconnected users are still there.

    This causes a miscount in how many participants are actually in the call that cannot be cleaned up without manually clearing redis, or starting a new room.

    Please let me know if there's something I can include to make this bug more clear. I may be able reproduce it on the livekit sample if I spam the server with lots of connections all at once.

    The only thing I see in the logs repeatedly is

    2021-04-05T03:51:51.950Z        ERROR   routing/redisrouter.go:317      error processing signal message{"error": "channel is full"}*RedisRouter).redisWorker
    2021-04-05T03:51:51.950Z        ERROR   routing/redisrouter.go:317      error processing signal message{"error": "channel is full"}*RedisRouter).redisWorker

    when this occurred

    opened by atbe 11
  • Sometimes clients will be stuck on the `connecting to wss://SERVER_URL/rtc?access_token=` message

    Sometimes clients will be stuck on the `connecting to wss://SERVER_URL/rtc?access_token=` message

    I'm not sure what logs to provide for this because it happens even on a fresh server boot. Here are the logs:

    2021-02-18T10:17:13.589Z        INFO    server/main.go:145      configured key provider {"num_keys": 1}
    2021-02-18T10:17:13.711Z        INFO    server/main.go:178      using multi-node routing via redis     {"address": "livespot-lk-redis-production:6379"}
    2021-02-18T10:17:13.714Z        INFO    service/roommanager.go:88       deleting room state     {"room": "2c035db5-8c1e-47df-903f-03e245b496fc"}
    2021-02-18T10:17:13.716Z        INFO    service/roommanager.go:88       deleting room state     {"room": "07fb1453-21ca-4cd8-ba51-28c5775ec56d"}
    2021-02-18T10:17:13.718Z        DEBUG   routing/redisrouter.go:288      starting redisWorker    {"node": "ND_uduvfI4D"}
    2021-02-18T10:17:13.718Z        INFO    service/server.go:110   starting LiveKit server {"address": ":7880", "nodeId": "ND_uduvfI4D", "version": "0.5.1"}
    2021-02-18T13:29:59.805Z        INFO    service/rtcservice.go:113       new client WS connected {"connectionId": "CO_YdqJFkYLMt8M", "room": "RM_XHgJhgiy8eFS", "roomName": "8fb5bc1e-1918-4240-9e05-b1c01420152c", "name": "0xFFC80bd2A413f37E125D39C281Cc85B88dcebF20"}
    2021-02-18T13:30:11.927Z        INFO    service/rtcservice.go:97        WS connection closed    {"participant": "0xFFC80bd2A413f37E125D39C281Cc85B88dcebF20", "connectionId": "CO_YdqJFkYLMt8M"}
    2021-02-18T13:30:15.610Z        INFO    service/rtcservice.go:113       new client WS connected {"connectionId": "CO_C2rQZ7M839Yn", "room": "RM_XHgJhgiy8eFS", "roomName": "8fb5bc1e-1918-4240-9e05-b1c01420152c", "name": "0xFFC80bd2A413f37E125D39C281Cc85B88dcebF20"}

    On the client side all we see is:

    connecting to wss://SERVER_URL/rtc?access_token=

    And in the network tab:



    The only solution to this that we've found is to reboot the livekit-server

    opened by atbe 10
  • Runtime error: Use of closed socket

    Runtime error: Use of closed socket

    Another one of these popped up today:

    2021-02-15T02:37:49.607Z        ERROR   service/rtcservice.go:131       source closed connection       {"participant": "0x46efc301B793a0d8C2999B11d8Bad43D1b4c4E8F"}*RTCService).ServeHTTP.func2
    2021-02-15T02:37:49.607Z        ERROR   service/rtcservice.go:157       error reading from websocket   {"error": "read tcp> use of closed network connection"}*RTCService).ServeHTTP
            /go/pkg/mod/[email protected]/negroni.go:46
            /go/pkg/mod/[email protected]/negroni.go:29
            /go/pkg/mod/[email protected]/negroni.go:38
            /go/pkg/mod/[email protected]/negroni.go:38*Recovery).ServeHTTP
            /go/pkg/mod/[email protected]/recovery.go:193
            /go/pkg/mod/[email protected]/negroni.go:38*Negroni).ServeHTTP
            /go/pkg/mod/[email protected]/negroni.go:96
    2021-02-15T02:37:49.607Z        INFO    service/rtcservice.go:95        WS connection closed    {"participant": "0x46efc301B793a0d8C2999B11d8Bad43D1b4c4E8F"}
    opened by atbe 10
  • RTCEngine.js:6 Uncaught (in promise) DOMException: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local offer sdp:

    RTCEngine.js:6 Uncaught (in promise) DOMException: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local offer sdp:

    Seeing this error again 0.3.3 again.

    Haven't been able to capture server logs yet.

    opened by atbe 6
  • Websocket connection fails sometimes upon connection

    Websocket connection fails sometimes upon connection

    Occasionally when the client connects to signal endpoint, it'll print out error reading from websocket and terminate the connection.

    opened by davidzhao 5
  • feat: support UDP in TURN

    feat: support UDP in TURN

    1. Add UDP option to TURN
    2. GetLocalIPAddress default to IPv4
    opened by hn8 5
  • Bridge rooms

    Bridge rooms


    from the documentation:

    In a multi-node setup, LiveKit can support a large number of concurrent rooms. However, there are limits to the number of participants in a room since, for now, a room must fit on a single node.

    My question would be if you have plans for publishing media across rooms? The main use case probably being a single speaker being heard/seen across different rooms. I'm eagerly waiting for the roadmap, but couldn't wait to ask that question after reading through the docs!

    opened by lukasIO 5
  • Production Ready

    Production Ready

    Hello, I tried this and it looks great to me. i read your online documentation. Its well documented. However, it says that it should be used in the same manner for production purposes. Can you help me more into explaining what would be the ideal way that this can be used in production.

    Since, it has docker. I am thinking of using AWS ECS for this. Would be great, If you can provide some context in that regard.

    Thank You

    opened by mohit67890 5
  • Propagate err2 if not nil

    Propagate err2 if not nil

    As far as I can tell, this conditional was meant to propagate err2 if it's not nil, but as written it tests against err instead.

    opened by alindeman 4
  • Send stun servers to clients

    Send stun servers to clients

    Flutter WebRTC stack requires the presence of STUN servers. For clients that are behind NATs, using STUN would also improve connectivity.

    opened by davidzhao 3
  • Recording support?

    Recording support?

    The server looks very promising since it's supported with mobile and web SDKs.

    However I could not see any section about recording in the documentation. Do you plan to add support for recording + processing recordings?

    opened by postacik 3
  • Ability to restrict participants from publishing data

    Ability to restrict participants from publishing data

    Currently any connected participant may publish data packets to the room. It'd be great if there's a way to limit that permission as part of the access token.

    I propose we introduce a canPublishData permission in the video grant. participants with it set to false should not be able to publish data.

    opened by davidzhao 0
  • Unpublish leaves tracks on peer connection

    Unpublish leaves tracks on peer connection

    Steps to reproduce:

    U1 connects -> publishes (successfully) U2 connects -> subscribes to U1 (successfully) U1 unpublishes + republishes -> U1 unSub + sub to U1

    (will add more logs / data shortly)

    opened by furqanrydhan 3
  • v0.11.1(Jul 23, 2021)


    • Fixed force_tcp flag, correctly suppress UDP candidates when enabled #62
    • Fixed participant actions with Room API in single node configuration #67
    • Fixed participants kicked out of the room sometimes when adaptive simulcast is used (f3a17a151f8641fe00851c2d047776f72d67677e)


    Huge shoutout to @hn8 for the contributions!

    • TURN/UDP support for improved connectivity #61
    • Updated logger, consistent field names #57 #60
    • Ability to have invisible participants (preparing for recorder) #65
    Source code(tar.gz)
    Source code(zip)
  • v0.11.0(Jul 16, 2021)

    We are introducing a new feature with v0.11 that significantly improve LiveKit's handling of simulcast, particularly on the publisher side. (#51) With v0.11, publishers can now indicate which layers they are actively publishing. This enables the SFU to place subscribers on currently active layers. Publishers could stop publishing to a particular layer due to bandwidth or CPU constraints.

    JS SDK > v0.10.x supports adaptive publishing

    Also in this release:

    • Improved connection error messaging with validate API (
    • Fixed Safari compatibility for H.264 rooms (
    • Use protobuf for initial roomJoin message #52
    Source code(tar.gz)
    Source code(zip)
  • v0.10.6(Jul 13, 2021)


    • Fixes down track resync on unmute


    • Exposes /debug/rooms endpoint when running in dev mode, which displays room and participant state along with down track stats
    Source code(tar.gz)
    Source code(zip)
  • v0.10.5(Jul 11, 2021)


    • Fix glitch during layer switch with H.264 simulcast
    • Handle client reconnect after server has been restarted (#43)
    • Enhancements to active-speaker detection (#44)
    • Improves handling of Node IP in container environments (#48)


    • When ports are not explicitly configured, and --dev flag is used, single port mode will be used to make it easier to map ports via Docker.
    Source code(tar.gz)
    Source code(zip)
  • v0.10.4(Jul 7, 2021)


    • Use multi-port mode by default (#40)
    • Optimized SFU send-loop to fully utilize all CPUs
    • Embedded TURN/TLS for strict corporate firewalls.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.9(Jun 11, 2021)

    Bugfixes and performance tuning.


    • Fixed potential deadlock when subscribers leave
    • Fixed deadlock during ICE restart
    • Improved test reliability


    • Single port performance enhancement, increase read buffer and warns if misconfigured


    • Ability to send data packets to specific participants (contributed by @FeepsDev)
    Source code(tar.gz)
    Source code(zip)
  • v0.9.6(Jun 4, 2021)

  • v0.9.4(May 23, 2021)


    • Handles ICE Restart much better than before
    • Upstream ion-sfu v1.10.3
    • Actually enforce CanSubscribe permissions


    • Ability to disable auto-subscribe behavior
    Source code(tar.gz)
    Source code(zip)
  • v0.9.3(May 16, 2021)


    • exports stats via Prometheus (when prometheus_port is set)
    • supports client-initiated ICE restart, especially when mobile networks change.


    • use_external_ip is not true by default - you should set this for production deploys.
    • updated to ion-sfu v1.10.0, pion v3.0.29
    Source code(tar.gz)
    Source code(zip)
  • v0.9.0(May 7, 2021)

    Simplified data channel usage with DataChannel V2. LiveKit now provides the ability to publish data payloads to the room without needing to use data tracks. Each client opens two data channels with the server.

    • reliable channel - delivery guaranteed, much like TCP.
    • lossy - best effort delivery, optimizes for getting data to clients asap.

    Clients now have a simple interface to publish data to the room via LocalParticipant.publishData

    Data tracks that were in place before v0.9.0 are now deprecated.

    Source code(tar.gz)
    Source code(zip)
  • v0.8.5(Apr 28, 2021)

    This release includes significant improvements to connectivity, with single port mode being the default. With this release, LiveKit requires only three ports with no limit* to the number of connected clients.

    • Primary API port (HTTP/WS)
    • UDP data port
    • TCP data port

    It also includes a couple of features and bugfixes:

    • Handle client-driven ICE restart - when client network conditions have changed, the server handles when client PeerConnection reconnects without losing session state
    • Bugfixes to single port mode (race conditions)
    • Participant.JoinedAt - indicates when participant joined the room
    • DeleteRoom now immediately terminates all connected clients (via Leave responses)
    Source code(tar.gz)
    Source code(zip)
  • v0.8.1(Apr 16, 2021)

    This release contains significant improvements to stability and connectivity.


    • Single-port mode: accepts ICE traffic over a single UDP port, demuxing to different participants
    • TCP mode: support for ICE/TCP in situations that UDP isn't available (like VPN, firewalls)
    • Plan B support: initial support for clients that are plan-b based.


    • Fixed potential race condition during ICE candidate exchange

    NOTE: there had been a breaking change to the config file, specifically:

    • rtc.ice_tcp_port is now ice. tcp_port
    • rtc.udp_port should be used to activate single port mode. port_range_start and port_range_end are no longer needed
    Source code(tar.gz)
    Source code(zip)
Open source platform for real-time audio and video
👾 Annie is a fast, simple and clean video downloader built with Go.

?? Annie is a fast, simple and clean video downloader built with Go. Installation Prerequisites Install via go get Homebrew (macOS only) Arch Linux Vo

Xinzhao Xu 15.1k Jul 24, 2021
Take control over your live stream video by running it yourself. Streaming + chat out of the box.

Take control over your content and stream it yourself. Explore the docs » View Demo · Use Our Server for Testing · FAQ · Report Bug Table of Contents

Owncast 4.9k Jul 20, 2021
Short video direct link acquisition 短视频直连获取工具

Glink 短视频去水印一键解析应用 Short video direct link acquisition 短视频直连获取工具 Glink是一款基于go语言开发的短视频解析应用,前端使用vue+argon主题,后端使用go-fiber框架,支持web在线模式、客户端模式。

佰阅 61 Jul 3, 2021
A Go implementation of fluent-ffmpeg

A Go implementation of fluent-ffmpeg

Modfy 274 Jul 15, 2021 is a video conferencing tool. is a video conferencing tool.

Bora Tanrıkulu 92 Jul 13, 2021
Golang bindings for FFmpeg

goav Golang binding for FFmpeg A comprehensive binding to the ffmpeg video/audio manipulation library. Usage import "

H. Giorgis 1.7k Jul 24, 2021
Parse and generate m3u8 playlists for Apple HTTP Live Streaming (HLS) in Golang (ported from gem

go-m3u8 Golang package for m3u8 (ported m3u8 gem go-m3u8 provides easy generation and parsing of m3u8 playlists d

Tan Quang Ngo 75 Jun 2, 2021
Personal video streaming server.

tube This is a Golang project to build a self hosted "tube"-style video player for watching your own video collection over HTTP or hosting your own ch

davy wybiral 199 Jul 15, 2021
Go bindings for libVLC and high-level media player interface

Go bindings for libVLC 2.X/3.X/4.X and high-level media player interface. The package can be useful for adding multimedia capabilities to applications

Adrian-George Bostan 224 Jul 20, 2021
live video streaming server in golang

中文 Simple and efficient live broadcast server: Very simple to install and use; Pure Golang, high performance, and cross-platform; Supports commonly us

浩麟 6.8k Jul 19, 2021
Live on-demand transcoding in go using ffmpeg. Also with NVIDIA GPU hardware acceleration.

Go live HTTP on-demand transcoding Transcoding is expensive and resource consuming operation on CPU and GPU. For big companies with thousands of custo

Miroslav Šedivý 42 Jul 22, 2021
A small program in Go that efficiently compresses videos using ffmpeg.

discordcompressor A small program in Go that efficiently compresses videos using ffmpeg. Dependencies FFmpeg including FFprobe Usage discordcompressor

null 5 Jul 16, 2021
Parser and generator of M3U8-playlists for Apple HLS. Library for Go language. :cinema:

M3U8 This is the most complete opensource library for parsing and generating of M3U8 playlists used in HTTP Live Streaming (Apple HLS) for internet vi

Alexander I.Grafov 841 Jul 17, 2021
Plays videos using Prometheus and Grafana, e.g. Bad Apple.

prometheus_video_renderer Plays videos using Prometheus and Grafana, e.g. Bad Apple. Modes Currently 3 different modes are supported. Bitmap The bitma

Jacob Colvin 44 Jul 11, 2021