Guides / Egress
Record or stream your LiveKit rooms
Depending on your request type, the egress service will either launch a web template in Chrome and connect to the room (room composite requests), or it will use the sdk directly (track and track composite requests). It uses GStreamer to encode, and can output to a file or to one or more streams.
Export an entire room's video and/or audio using a web layout rendered by chrome. Always transcoded.
Example use case: recording a meeting for team members to watch later.
Sync and export up to one audio and one video track. Will transcode and mux.
Example use case: exporting audio+video from many cameras at once during a production, for use in additional post-production.
Export individual tracks directly. Video tracks are not transcoded.
Example use case: streaming an audio track to a captioning service via websocket.
Egress Type | MP4 File | OGG File | IVF File | Rtmp(s) Stream | Websocket Stream |
---|---|---|---|---|---|
Room Composite | ✅ | ✅ | ✅ | ||
Track Composite | ✅ | ✅ | ✅ | ||
Track | ✅ | ✅ | ✅ | ✅ |
Files can be uploaded to any S3 compatible storage, Azure, or GCP.
All RPC definitions and options can be found here.
Egress service requires roomRecord
permissions in Access Tokens
The Egress API exists within our server SDKs and CLI
The API is part of LiveKit Server, which uses redis to communicate with the Egress service.
Starts a room composite egress (uses a web template).
const egressClient = new EgressClient('https://my-livekit-host','livekit-api-key','livekit-api-secret');const output = {fileType: EncodedFileType.MP4,filepath: 'livekit-demo/room-composite-test.mp4',s3: {accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket'}};const info = await egressClient.startRoomCompositeEgress('my-room', 'speaker-dark', output);const egressID = info.egressId;
ctx := context.Background()egressClient := lksdk.NewEgressClient("https://my-livekit-host","livekit-api-key","livekit-api-secret",)fileRequest := &livekit.RoomCompositeEgressRequest{RoomName: "my-room",Layout: "speaker-dark",Output: &livekit.RoomCompositeEgressRequest_File{File: &livekit.EncodedFileOutput{FileType: livekit.EncodedFileType_MP4,Filepath: "livekit-demo/my-room-test.mp4",Output: &livekit.EncodedFileOutput_S3{S3: &livekit.S3Upload{AccessKey: "aws-access-key",Secret: "aws-access-secret",Region: "aws-region",Bucket: "my-bucket",},},},},}info, err := egressClient.StartRoomCompositeEgress(ctx, fileRequest)egressID := info.EgressId
require 'livekit'const egressClient = LiveKit::EgressServiceClient.new("https://your-url",api_key: 'key',api_secret: 'secret');info = egressClient.start_room_composite_egress('room-name',LiveKit::Proto::EncodedFileOutput.new(file_type: LiveKit::Proto::EncodedFileType::MP4,filepath: "dz-test-recording.mp4",s3: LiveKit::Proto::S3Upload.new(access_key: 'access-key',secret: 'secret',region: 'bucket-region',bucket: 'bucket')))puts info
{"room_name": "my-room","layout": "speaker-dark","file": {"file_type": "MP4","filepath": "livekit-demo/my-room-test.mp4","s3": {"access_key": "aws-access-key","secret": "aws-access-secret","region": "aws-region","bucket": "my-bucket"}}}
export LIVEKIT_URL=https://my-livekit-hostexport LIVEKIT_API_KEY=livekit-api-keyexport LIVEKIT_API_SECRET=livekit-api-secretlivekit-cli start-room-composite-egress --request request.json
Egress started. Egress ID: EG_XXXXXXXXXXXX
fileRequest.Output.File.Output
can be left empty if one of s3
, azure
, or gcp
is supplied with your config (see below).fileRequest.Output.File.Filepath
can be left empty, and a unique filename will be generated based on the date and room name.Built-in layouts include speaker-dark
, speaker-light
, grid-dark
, and grid-light
.
You can also build your own layouts. You likely already have a room UI built with LiveKit web SDKs - the recording UI can be similar to your existing room UI, with a few differences:
canSubscribe
and hidden
set to trueSource code to our default room templates can be found here, and the Template SDK for building your own templates can be found here.
Starts a track composite egress with up to one audio track and one video track. Track IDs can be found using webhooks or one of the server SDKs.
const output = {fileType: EncodedFileType.MP4,filepath: 'livekit-demo/track-composite-test.mp4',s3: {accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket'}};const info = await egressClient.startTrackCompositeEgress('my-room', output, audioTrackID, videoTrackID);const egressID = info.egressId;
request := &livekit.TrackCompositeEgressRequest{RoomName: "my-room",AudioTrackId: audioTrackID,VideoTrackId: videoTrackID,Output: &livekit.TrackCompositeEgressRequest_File{File: &livekit.EncodedFileOutput{FileType: livekit.EncodedFileType_MP4,Filepath: "livekit-demo/track-composite-test.mp4",Output: &livekit.EncodedFileOutput_S3{S3: &livekit.S3Upload{AccessKey: "aws-access-key",Secret: "aws-access-secret",Region: "aws-region",Bucket: "my-bucket",},},},},}info, err := egressClient.StartTrackCompositeEgress(ctx, request)egressID := info.EgressId
# require a special type for arrays, which enforces type# RTMP simulcast is supportedurls = Google::Protobuf::RepeatedField.new(:string, ['rtmp://url1', 'rtmps://url2'])info = egressClient.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 info
{"room_name": "my-room","audio_track_id": "TR_XXXXXXXXXXXX","video_track_id": "TR_XXXXXXXXXXXX","file": {"file_type": "MP4","filepath": "livekit-demo/track-composite-test.mp4","s3": {"access_key": "aws-access-key","secret": "aws-access-secret","region": "aws-region","bucket": "my-bucket"}}}
livekit-cli start-track-composite-egress --request request.json
Egress started. Egress ID: EG_XXXXXXXXXXXX
Starts a track egress. Track ID can be found using webhooks or one of the server SDKs.
const output = {fileType: EncodedFileType.MP4,filepath: 'livekit-demo/track-test.mp4',s3: {accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket'}};const info = await egressClient.startTrackEgress('my-room', trackID, output);const egressID = info.egressId;
trackRequest := &livekit.TrackEgressRequest{RoomName: "my-room",TrackId: "speaker-dark",Output: &livekit.TrackEgressRequest_File{File: &livekit.DirectFileOutput{Filepath: "livekit-demo/track-test",Output: &livekit.DirectFileOutput_S3{S3: &livekit.S3Upload{AccessKey: "aws-access-key",Secret: "aws-access-secret",Region: "aws-region",Bucket: "my-bucket",},},},},}info, err := egressClient.StartTrackEgress(ctx, trackRequest)egressID := info.EgressId
info = egressClient.start_track_egress('room-name',LiveKit::Proto::DirectFileOutput.new(filepath: 'myfile.ivf',gcp: LiveKit::Proto::GCPUpload.new(credentials: '',bucket: 'my-bucket')),'TR_XXXXXXXXXXXX',)puts info
{"room_name": "my-room","track_id": "TR_XXXXXXXXXXXX","file": {"filepath": "livekit-demo/track-test.mp4","s3": {"access_key": "aws-access-key","secret": "aws-access-secret","region": "aws-region","bucket": "my-bucket"}}}
livekit-cli start-track-egress --request request.json
Egress started. Egress ID: EG_XXXXXXXXXXXX
Used to change the web layout on an active RoomCompositeEgress.
const info = await egressClient.updateLayout(egressID, 'grid-light');
info, err := egressClient.UpdateLayout(ctx, &livekit.UpdateLayoutRequest{EgressId: egressID,Layout: "grid-light",})
egressClient.update_layout('egress-id', 'grid-dark')
livekit-cli update-layout --id EG_XXXXXXXXXXXX --layout grid-light
Used to add or remove stream urls from an active stream
Note: you can only add or remove outputs from a stream (RTMP output instead of filepath).
const output = {protocol: StreamProtocol.RTMP,urls: ['rtmp://live.twitch.tv/app/<stream-key>']};var info = await egressClient.startRoomCompositeEgress('my-room', 'speaker-dark', output);const streamEgressID = info.egressId;info = await egressClient.updateStream(streamEgressID,['rtmp://a.rtmp.youtube.com/live2/stream-key']);
streamRequest := &livekit.RoomCompositeEgressRequest{RoomName: "my-room",Layout: "speaker-dark",Output: &livekit.RoomCompositeEgressRequest_Stream{Stream: &livekit.StreamOutput{Protocol: livekit.StreamProtocol_RTMP,Urls: []string{"rtmp://live.twitch.tv/app/<stream-key>"},},},}info, err := egressClient.StartRoomCompositeEgress(ctx, streamRequest)streamEgressID := info.EgressIdinfo, err = egressClient.UpdateStream(ctx, &livekit.UpdateStreamRequest{EgressId: streamEgressID,AddOutputUrls: []string{"rtmp://a.rtmp.youtube.com/live2/<stream-key>"}})
# to add streamsegressClient.update_stream('egress-id',add_output_urls: ['rtmp://new-url'],remove_output_urls: ['rtmp://old-url'])
livekit-cli update-stream \--id EG_XXXXXXXXXXXX \--add-urls "rtmp://a.rtmp.youtube.com/live2/stream-key"
Used to list active egress. Does not include completed egress.
const res = await egressClient.listEgress();
res, err := egressClient.ListEgress(ctx, &livekit.ListEgressRequest{})
# to list egress on myroomegressClient.list_egress(room_name: 'myroom')# to list all egressesegressClient.list_egress()
livekit-cli list-egress
Stops an active egress.
const info = await egressClient.stopEgress(egressID);
info, err := egressClient.StopEgress(ctx, &livekit.StopEgressRequest{EgressId: egressID,})
egressClient.stop_egress('egress-id')
livekit-cli stop-egress --id EG_XXXXXXXXXXXX
See the deployment docs for more info on deployment, config, and autoscaling.
Previous
Webhooks