WebRTC Insertable Streams for End-to-End Encryption

This article explains how the WebRTC Insertable Streams API (also known as WebRTC Encoded Transform) enables true end-to-end encryption (E2EE) in JavaScript applications. It breaks down the limitation of standard WebRTC encryption in multi-party conferences, describes how insertable streams intercept encoded media frames before transmission, and demonstrates how custom cryptographic layers can be implemented in a browser environment to secure media from intermediate routing servers.

The WebRTC Encryption Challenge in Multi-Party Calls

Standard WebRTC natively uses DTLS (Datagram Transport Layer Security) and SRTP (Secure Real-time Transport Protocol) to encrypt voice and video traffic. While this provides secure peer-to-peer communication, multi-party video conferencing typically relies on a central Selective Forwarding Unit (SFU) to scale efficiently.

In a traditional SFU architecture, DTLS-SRTP terminates at the media server. The SFU decrypts incoming media packets to inspect metadata (like spatial or temporal layers) and re-encrypts them before forwarding to other participants. As a result, the server operator has access to the unencrypted audio and video, preventing true end-to-end encryption.

How Insertable Streams Solve the Problem

The Insertable Streams specification introduces a mechanism to intercept raw, encoded media frames within the browser pipeline. Instead of allowing the browser to immediately packetize and transmit the output of a video or audio codec, the API exposes the encoded frames as a ReadableStream and WritableStream via a TransformStream.

This architecture places a processing hook directly between: 1. The Encoder and Packetizer on the sender’s side. 2. The Depacketizer and Decoder on the receiver’s side.

By exposing these streams in JavaScript or Web Workers, developers can insert custom cryptographic operations directly on the encoded frame data before the browser applies standard transport-layer encryption.

The End-to-End Encryption Workflow

Implementing E2EE with Insertable Streams follows a four-step pipeline:

Sender:    [Media Stream] -> [Encoder] -> [Custom Encryption] -> [SRTP/DTLS] -> (Network)
                                                                                  |
Receiver:  [Media Stream] <- [Decoder] <- [Custom Decryption] <- [SRTP/DTLS] <-- (Network)

1. Frame Interception (Sender)

When a sender captures audio or video, the browser encodes the raw media into encoded frames (such as VP8, VP9, AV1, or Opus). Using the RTCRtpSender.createEncodedStreams() method (or RTCRtpScriptTransform), the application intercepts the stream of encoded chunks (RTCEncodedAudioFrame or RTCEncodedVideoFrame).

2. Custom Payload Encryption

Inside a dedicated TransformStream (typically running inside a Web Worker to avoid blocking the main UI thread), the application encrypts the frame’s payload using standard symmetric ciphers, such as AES-GCM or AES-CTR:

3. Transport and Routing

The custom-encrypted frame is passed back to the WebRTC pipeline, which applies standard DTLS-SRTP encryption before transmission over the network. When the SFU receives the stream, it terminates the DTLS-SRTP layer, inspects the unencrypted routing metadata, and forwards the packet. Because the underlying payload remains protected by the application-layer encryption, the SFU cannot access the raw media.

4. Frame Interception and Decryption (Receiver)

On the receiving client, the incoming packet passes through the standard DTLS-SRTP decryption layer. Before the frame reaches the browser’s hardware or software decoder:

Key Advantages of Insertable Streams