End-to-end encryption

Secure your realtime media tracks with E2EE.

Overview

LiveKit includes built-in support for end-to-end encryption (E2EE) on realtime audio and video tracks. With E2EE enabled, media data remains fully encrypted from sender to receiver, ensuring that no intermediaries (including LiveKit servers) can access or modify the content. This feature is:

  • Available for both self-hosted and LiveKit Cloud customers at no additional cost.
  • Ideal for regulated industries and security-critical applications.
  • Designed to provide an additional layer of protection beyond standard transport encryption.
Note

Security is our highest priority. Learn more about our comprehensive approach to security.

How E2EE works

E2EE is enabled at the room level and automatically applied to all media tracks from all participants in that room. You must enable it within the LiveKit SDK for each participant. In many cases you can use a built-in key provider with a single shared key for the whole room. If you require unique keys for each participant, or key rotation during the lifetime of a single room, you can implement your own key provider.

Key distribution

It is your responsibility to securely generate, store, and distribute encryption keys to your application at runtime. LiveKit does not (and cannot) store or transport encryption keys for you.

If using a shared key, you would typically generate it on your server at the same time that you create a room and distribute it securely to participants alongside their access token for the room. When using unique keys per participant, you may need a more sophisticated method for distributing keys as new participants join the room. Remember that the key is needed for both encryption and decryption, so even when using per-participant keys, you must ensure that all participants have all keys.

Limitations

All LiveKit network traffic is encrypted using TLS, but full end-to-end encryption applies only to media tracks and is not applied to realtime data messages, API calls, or other signaling.

Implementation guide

These examples show how to use the built-in key provider with a shared key. If you need to use a custom key provider, see the section below.

// 1. Initialize the external key provider
const keyProvider = new ExternalE2EEKeyProvider();
// 2. Configure room options
const roomOptions: RoomOptions = {
e2ee: {
keyProvider: keyProvider,
// Required for web implementations
worker: new Worker(new URL('livekit-client/e2ee-worker', import.meta.url)),
},
};
// 3. Create and configure the room
const room = new Room(roomOptions);
// 4. Set your externally distributed encryption key
await keyProvider.setKey(yourSecureKey);
// 5. Enable E2EE for all local tracks
await room.setE2EEEnabled(true);
// 6. Connect to the room
await room.connect(url, token);

Example implementation

For a production-ready implementation, refer to our Meet example app which demonstrates E2EE in a production-grade application using the ExternalE2EEKeyProvider.

Using a custom key provider

If your application requires key rotation during the lifetime of a single room or unique keys per participant (such as when implementing the MEGOLM or MLS protocol), you'll need to implement your own key provider. The full details of that are beyond the scope of this guide, but a brief outline for the JS SDK is provided below (the process is similar in the other SDKs as well):

  1. Extend the BaseKeyProvider class.
  2. Call onSetEncryptionKey with each key/identity pair
  3. Set appropriate ratcheting options (ratchetSalt, ratchetWindowSize, failureTolerance, keyringSize).
  4. Implement the onKeyRatcheted method to handle key updates.
  5. Call ratchetKey() when key rotation is needed.
  6. Pass your custom key provider in the room options, in place of the built-in key provider.