Skip to main content

E2EE with agents

Enable end-to-end encryption for LiveKit Agents.

Overview

A LiveKit agent is just another participant in the room, so it needs the shared encryption key to publish and subscribe to encrypted media. The same key encrypts the agent's outbound audio (such as TTS) and decrypts inbound media from clients (such as user speech for STT). Pass an E2EEOptions to ctx.connect inside your job entrypoint, using the same shared key the clients use.

See Key distribution for guidance on delivering the shared key to your agent and clients securely.

Enable E2EE in your agent

Connect to the room with ctx.connect before starting your AgentSession. If you let AgentSession.start connect for you, there's no place to pass encryption options.

import os
from livekit import rtc
from livekit.agents import JobContext, AgentSession
@server.rtc_session(agent_name="my-agent")
async def entrypoint(ctx: JobContext):
# Connect with E2EE before starting the session
await ctx.connect(
encryption=rtc.E2EEOptions(
key_provider_options=rtc.KeyProviderOptions(
shared_key=os.environ["LIVEKIT_E2EE_KEY"].encode(),
),
),
)
session = AgentSession(
# ... configure your session ...
)
await session.start(agent=MyAgent(), room=ctx.room)
import { JobContext, defineAgent, voice } from '@livekit/agents';
import type { E2EEOptions } from '@livekit/rtc-node';
export default defineAgent({
entry: async (ctx: JobContext) => {
const e2ee: E2EEOptions = {
keyProviderOptions: {
sharedKey: new TextEncoder().encode(process.env.LIVEKIT_E2EE_KEY!),
},
};
// Connect with E2EE before starting the session
await ctx.connect(e2ee);
const session = new voice.AgentSession({ /* ... configure your session ... */ });
await session.start({ agent: new MyAgent(), room: ctx.room });
},
});
Missing or mismatched key

If the agent connects to a room with E2EE enabled but doesn't pass a matching key, it can't decrypt inbound media. The agent joins, but STT never produces transcripts, so the LLM never receives input and the agent never speaks. Check the agent logs for decryption errors and confirm the shared key matches the one used by clients.

Distributing the key to your agent

Treat the shared key like any other secret. Common patterns:

  • Load it from an environment variable or secret manager at worker startup.
  • Pass it through job metadata when dispatching the agent, so different rooms can use different keys.
  • Don't hardcode keys in source.

Per-participant keys and key rotation

This page only covers the shared-key case. If your application requires unique keys per participant or key rotation during a room's lifetime, you'll need a custom key provider. See Using a custom key provider for details.

Examples