Skip to main content

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:

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:

  1. Your backend calls the StartRoomCompositeEgress() API.
  2. LiveKit assigns an available egress instance to handle the request.
  3. 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 to StartRoomCompositeEgress().
  4. The egress recorder loads the constructed URL in a headless Chrome instance.
  5. The recorder waits for the page to log START_RECORDING to the console, then begins recording.
  6. The recorder waits for the page to log END_RECORDING to 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 url and token query parameters.
  • Render the view you want recorded.
  • Log START_RECORDING when the view is ready and END_RECORDING when 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:

MethodDescription
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 grid
if (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.

Custom template or track egress

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:

  1. Edit the SpeakerLayout.tsx file to move the FocusLayout above the CarouselLayout:

    return (
    <div className="lk-focus-layout">
    <FocusLayout trackRef={mainTrack as TrackReference} />
    <CarouselLayout tracks={remainingTracks}>
    <ParticipantTile />
    </CarouselLayout>
    </div>
    );
  2. Edit App.css to override the default .lk-focus-layout columns. The component library sets 1fr 5fr; reverse them to 5fr 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, and Track.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 RoomAudioRenderer
tr.publication.kind === Track.Kind.Video &&
tr.participant.identity !== room.localParticipant.identity,
);
Egress participant is subscribe-only

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.

No screen share simulation

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.

  1. Change directory to template-default and start the default template server:

    cd /path/to/egress/template-default
    pnpm install
    pnpm dev

    The server is available at http://localhost:5173. Use this as your base-url in the next step.

  2. Use the lk egress test-template command to test your template:

    lk egress test-template \
    --base-url http://localhost:5173 \
    --room my-room \
    --layout grid \
    --publishers 4

    This lk egress test-template command creates a room named my-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-urlstringyesBase URL of your template, for example https://recorder.example.com. The command appends the url, token, and layout query parameters.
--publishersintyesNumber of simulated publishers to add to the room. Each one publishes a demo video track.
--roomstringName of the room to create. Defaults to an auto-generated name if omitted.

--layout

string

Layout name passed to the template as the layout query parameter.

Valid values: grid, speaker, single-speaker.

You can optionally add the -light suffix to any layout type to change the background color to white. For example, grid-light.

Additional resources

The following resources provide more information about custom recording templates.