Overview
LiveKit RoomComposite egress records all participants in a room by rendering a web app and capturing its output. The default recording view works without any setup, but a custom template gives you full control over what the recording shows: which tracks appear, how they're arranged, and page layout.
Default recording view
The default view uses LiveKit's React Components. If you only need to customize the arrangement of participants, or audio and video quality, you can modify the following configuration options:
Layout: control the arrangement of participants in the view. You can set or change the layout using eitherStartRoomCompositeEgress()orUpdateLayout().EncodingOptions: control the quality of the audio and video captured.
For more advanced customizations, build a custom template as described in the rest of this guide.
How custom templates work
A custom template is a basic web app. You can build it with any framework, host it yourself, and pass its URL to the egress API.
Your template runs inside a headless Chrome instance controlled by the egress service, which passes connection details to your app as URL query parameters. Your app signals back by logging specific strings (START_RECORDING, END_RECORDING) to the browser console.
The workflow is as follows:
- Your backend calls the
StartRoomCompositeEgress()API. - LiveKit assigns an available egress instance to handle the request.
- The egress recorder constructs the web page URL, appending these query parameters:
url: URL of the LiveKit server.token: Access token for joining the room as a hidden recorder participant.layout: Layout name passed toStartRoomCompositeEgress().
- The egress recorder loads the constructed URL in a headless Chrome instance.
- The recorder waits for the page to log
START_RECORDINGto the console, then begins recording. - The recorder waits for the page to log
END_RECORDINGto the console, then finalizes the recording.
No matter which framework you use, your template code must do the following:
- Connect to the room using the
urlandtokenquery parameters. - Render the view you want recorded.
- Log
START_RECORDINGwhen the view is ready andEND_RECORDINGwhen the session is over.
The template SDK handles connection parameters and recording signals for you.
Template SDK
The template SDK (@livekit/egress-sdk ) is a small library that reads the egress query parameters and emits the recording signals for you. Use it in any custom template, regardless of framework.
Import the EgressHelper default export:
import EgressHelper from '@livekit/egress-sdk';
It provides the following methods:
| Method | Description |
|---|---|
getLiveKitURL() | Returns the LiveKit server URL from the url query parameter. |
getAccessToken() | Returns the recorder access token from the token query parameter. |
getLayout() | Returns the current layout name. |
setRoom(room) | Registers your connected Room instance. The SDK ends the recording automatically when the room disconnects. |
startRecording() | Signals the recorder to begin recording. |
endRecording() | Signals the recorder to stop and finalize the recording. |
onLayoutChanged(callback) | Registers a callback that runs when the layout is changed with UpdateLayout(). |
Build a custom recording view
You can use any web framework, but the easiest way to get started is with the default React template. Copy the source files from the template-default directory in the LiveKit egress repository.
The src directory includes the following files:
template-default/src/├── App.css # Styles for the recording view and layouts├── App.tsx # Root component: reads the egress query parameters and renders the recording view├── Room.tsx # Main recording view: selects tracks and chooses a layout├── SingleSpeakerLayout.tsx # Component used for the `single-speaker` layout├── SpeakerLayout.tsx # Component used for the `speaker` layout├── index.css # Global base styles for the app (body and font defaults)└── index.tsx # Entry point: mounts the React app into the page
Example: Record only the screen share
This example shows how to modify the default view using template-default to record only the screen share. By default, Room.tsx composites every camera and screen share in the room. Some use cases are better suited to a narrower view. For example, during a coding exercise, an interview platform might record only the candidate's screen share while capturing audio from everyone in the room.
The default Room.tsx selects camera, screen share, and unknown-source tracks:
const allTracks = useTracks([Track.Source.Camera, Track.Source.ScreenShare, Track.Source.Unknown],{onlySubscribed: true,},);
To record only the screen share, render screenshareTracks in a single GridLayout. screenshareTracks is an array of screen share tracks initialized in the CompositeTemplate function. Replace the layout selection logic in Room.tsxwith the following code:
// Replace the layout selection logic with a single gridif (room.state !== ConnectionState.Disconnected) {main = (<GridLayout tracks={screenshareTracks}><ParticipantTile /></GridLayout>);}
With a single screen share track in the room, GridLayout renders it at full size. RoomAudioRenderer plays audio from every participant, so voices remain in the recording even though camera feeds aren't shown.
If you only need the raw screen share track and nothing else, track egress exports it directly without compositing. A track egress exports a single track, so it can't include audio from other participants. Use a custom template when you need the screen share combined with room audio.
Example: Move non-speaking participants to the right side of the speaker view
The default Speaker view in template-default shows the non-speaking participants on the left and the speaker on the right. To put the speaker on the left and the non-speaking participants on the right, make the following changes:
Edit the
SpeakerLayout.tsxfile to move theFocusLayoutabove theCarouselLayout:return (<div className="lk-focus-layout"><FocusLayout trackRef={mainTrack as TrackReference} /><CarouselLayout tracks={remainingTracks}><ParticipantTile /></CarouselLayout></div>);Edit
App.cssto override the default.lk-focus-layoutcolumns. The component library sets1fr 5fr; reverse them to5fr 1fr:.lk-focus-layout {height: 100%;grid-template-columns: 5fr 1fr;}
Preview the changes with the lk egress test-template command. For details, see Test your template.
Filter tracks and participants
The screen share example filters by track source, but the useTracks hook returns an array that you can use to select tracks based on any track or participant property. Common options include the following:
- Track source: select cameras, screen shares, or microphones with
Track.Source.Camera,Track.Source.ScreenShare, andTrack.Source.Microphone. - Participant identity: record or exclude a specific participant with
tr.participant.identity. - Participant kind: record only the agent or human participants by checking
tr.participant.kind. - Participant attributes or metadata: filter on values you set yourself, such as a role on each participant, with
tr.participant.attributes.
In the Room.tsx file, see filteredTracks for an example of how to filter tracks based on these properties. The following code filters out the egress recorder participant and audio tracks:
const filteredTracks = allTracks.filter((tr) =>// Filter only for video tracks and ignore the egress recorder participant// Audio is handled separately by RoomAudioRenderertr.publication.kind === Track.Kind.Video &&tr.participant.identity !== room.localParticipant.identity,);
The egress recorder is a subscribe-only participant. It doesn't publish any tracks, so filtering out the egress participant is strictly a defensive guard.
Test your template
The lk egress test-template CLI command previews a custom recording template in your browser, populated with simulated participants. This doesn't produce a recording: it opens your template the same way the egress recorder does, so you can check the layout before deploying.
There is no screen share simulation. If you're testing the template from Example: Record only the screen share, the layout preview in your browser is empty.
The following steps require pnpm .
The lk egress test-template command uses your configured LiveKit project credentials to generate the recorder token. Set the LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET environment variables, or authenticate with lk cloud auth.
Change directory to
template-defaultand start the default template server:cd /path/to/egress/template-defaultpnpm installpnpm devThe server is available at
http://localhost:5173. Use this as yourbase-urlin the next step.Use the
lk egress test-templatecommand to test your template:lk egress test-template \--base-url http://localhost:5173 \--room my-room \--layout grid \--publishers 4This
lk egress test-templatecommand creates a room namedmy-room, adds four virtual publishers who publish simulated video streams, and opens a browser instance to your app URL with the correct parameters:http://localhost:5173?url=<LIVEKIT_URL>&layout=grid&token=<RECORDER_TOKEN>.
For a full description of the available flags, see Test template CLI reference.
Deploy your custom template
Your custom template is a basic web app. For production, host your app on any static web host, such as Vercel .
After you deploy, use the public URL as the custom_base_url parameter for the StartRoomCompositeEgress() API.
For authentication, append query string parameters to the base URL. For example, https://your-template-url.example.com/?yourparam={auth_info} carries an auth_info value your template can use to authenticate the user. Set this as your custom_base_url.
Test template CLI reference
Test an egress template with the lk egress test-template command. For an example, see Test your template.
The command adds the requested number of simulated publishers to a room, builds a recorder token, and opens your default browser at <base-url>/?url=<server-url>&layout=<layout>&token=<token>. It simulates active speakers until you stop it with Ctrl+C.
The following command line flags are available:
| Flag | Type | Required | Description |
|---|---|---|---|
--base-url | string | yes | Base URL of your template, for example https://recorder.example.com. The command appends the url, token, and layout query parameters. |
--publishers | int | yes | Number of simulated publishers to add to the room. Each one publishes a demo video track. |
--room | string | Name of the room to create. Defaults to an auto-generated name if omitted. | |
| string | Layout name passed to the template as the layout query parameter. Valid values: You can optionally add the |
Additional resources
The following resources provide more information about custom recording templates.