Use this SDK to interact with LiveKit server APIs and create access tokens from your Ruby backend.
This library is designed to work with Ruby 3.1 and above.
Add this line to your application's Gemfile:
gem 'livekit-server-sdk'and then bundle install.
gem install livekit-server-sdkv1.0 is a breaking release. The most important change is behavioral: service methods now return the response message directly and raise on failure, instead of returning a Twirp::ClientResp that you had to unwrap and error-check yourself.
In 0.x, every call returned a Twirp::ClientResp: you read the result from .data, and a failed call came back with a non-nil .error. Nothing was raised, so an unchecked failure silently surfaced later as a nil result.
In 1.x, the result is returned directly, and failures raise LiveKit::ServerError (or LiveKit::SipCallError for SIP dialing calls).
# 0.x — unwrap .data, check .error manually
resp = client.create_room('myroom')
if resp.error
# handle failure
else
room = resp.data
end
# 1.x — result returned directly, failures raise
begin
room = api.room.create_room('myroom')
rescue LiveKit::ServerError => e
# e.code, e.message, e.metadata
endSee Error handling below for details, including the SIP-specific LiveKit::SipCallError.
0.x constructed each service client on its own. 1.x adds LiveKit::LiveKitAPI, a single entry point that exposes every service (room, egress, ingress, sip, agent_dispatch, connector) over a shared connection.
# 0.x
client = LiveKit::RoomServiceClient.new('https://my.livekit.instance',
api_key: 'yourkey', api_secret: 'yoursecret')
client.list_rooms
# 1.x
api = LiveKit::LiveKitAPI.new('https://my.livekit.instance',
api_key: 'yourkey', api_secret: 'yoursecret')
api.room.list_roomsThe individual clients (LiveKit::RoomServiceClient, etc.) still exist and take the same arguments, so you can adopt the new error handling first and switch to LiveKitAPI later — but note they raise on failure now too.
- Token authentication — construct
LiveKitAPI(or a client) with a pre-signedtoken:instead of an API key/secret, for client-side use where the secret must not be exposed. See Authentication. - Bug fixes:
start_participant_egressno longer raises when given a single output;AgentDispatchServiceClient#get_dispatch/#list_dispatchnow return correctly.
Creating a token for participant to join a room.
require 'livekit'
token = LiveKit::AccessToken.new(api_key: 'yourkey', api_secret: 'yoursecret')
token.identity = 'participant-identity'
token.name = 'participant-name'
token.video_grant = LiveKit::VideoGrant.new(roomJoin: true, room: 'room-name')
token.attributes = { "mykey" => "myvalue" }
puts token.to_jwtBy default, a token expires after 6 hours. You may override this by passing in ttl when creating the token. ttl is expressed in seconds.
It's possible to customize the permissions of each participant. See more details at access tokens guide.
Every request to the server APIs is authenticated. There are two modes:
- API key & secret — recommended for backend use. The SDK signs a short-lived token per request from your key and secret. Keep your API secret on the server; never ship it to a client.
- Access token — for frontend / client-side use, where the API secret must not be exposed. Pass a pre-signed access token that already carries the grants for the operations you'll perform; the SDK sends it verbatim.
# backend (API key & secret): set LIVEKIT_URL, LIVEKIT_API_KEY, and
# LIVEKIT_API_SECRET, then construct with no arguments...
api = LiveKit::LiveKitAPI.new
# ...or pass any of them explicitly to override the corresponding env var:
api = LiveKit::LiveKitAPI.new('https://my.livekit.instance', api_key: 'yourkey', api_secret: 'yoursecret')
# frontend (pre-signed access token): with LIVEKIT_URL set, pass just the token:
api = LiveKit::LiveKitAPI.new(token: 'a-pre-signed-token')The url and credentials fall back to the LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, and LIVEKIT_TOKEN environment variables. Values you pass explicitly take precedence; the environment variables are used only as a fallback for arguments you omit — an ambient LIVEKIT_TOKEN, for example, won't override an explicitly-provided API key and secret.
LiveKit::LiveKitAPI is a single entry point to every server API, exposing each service through a reader: room, egress, ingress, sip, agent_dispatch, and connector. Each method returns the response message directly and raises LiveKit::ServerError on failure. See service apis for the full list.
require 'livekit'
api = LiveKit::LiveKitAPI.new('https://my.livekit.instance',
api_key: 'yourkey', api_secret: 'yoursecret')
name = 'myroom'
room = api.room.create_room(name)
api.room.list_rooms
api.room.list_participants(room: name)
api.room.mute_published_track(room: name, identity: 'participant',
track_sid: 'track-id', muted: true)
api.room.remove_participant(room: name, identity: 'participant')
api.room.delete_room(room: name)Failed API calls raise LiveKit::ServerError, which exposes the error code, message, and any server-provided metadata. SIP dialing calls raise LiveKit::SipCallError (a ServerError subclass) that also exposes the SIP status:
begin
api.sip.create_sip_participant('trunk-id', '+15105550100', 'my-room', wait_until_answered: true)
rescue LiveKit::SipCallError => e
puts e # e.g. "SIP call failed: 486 Busy Here (resource_exhausted)"
puts e.sip_status_code # 486
rescue LiveKit::ServerError => e
puts e.code
endThe per-service clients (LiveKit::RoomServiceClient, etc.) can also be constructed individually with the same arguments.
Egress is reached via api.egress. Refer to docs for more usage examples.
require 'livekit'
api = LiveKit::LiveKitAPI.new('https://your-url', api_key: 'key', api_secret: 'secret')
# starting a room composite to S3
info = api.egress.start_room_composite_egress(
'room-name',
LiveKit::Proto::EncodedFileOutput.new(
file_type: LiveKit::Proto::EncodedFileType::MP4,
filepath: "my-recording.mp4",
s3: LiveKit::Proto::S3Upload.new(
access_key: 'access-key',
secret: 'secret',
region: 'bucket-region',
bucket: 'bucket'
)
)
)
puts info
# starting a track composite to RTMP
urls = Google::Protobuf::RepeatedField.new(:string, ['rtmp://url1', 'rtmps://url2'])
info = api.egress.start_track_composite_egress(
'room-name',
LiveKit::Proto::StreamOutput.new(
protocol: LiveKit::Proto::StreamProtocol::RTMP,
urls: urls
),
audio_track_id: 'TR_XXXXXXXXXXXX',
video_track_id: 'TR_XXXXXXXXXXXX'
)
puts infoYou may store credentials in environment variables. When the corresponding argument is not passed to LiveKitAPI (or AccessToken), these are used:
LIVEKIT_URLLIVEKIT_API_KEYLIVEKIT_API_SECRETLIVEKIT_TOKEN
The gem is available as open source under the terms of Apache 2.0 License.
| 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 |