WebRTC: Serverless Real-Time Communication Between Browsers
Open a video call in your browser and, more often than not, the audio, video, and chat messages travel directly between browsers rather than through a server. That is WebRTC (Web Real-Time Communication), a bundle of signaling, NAT traversal, encryption, and data-transport technologies that brought P2P communication to the most widely deployed platform there is.
What WebRTC is
WebRTC is a family of APIs and protocols that let browsers and mobile apps exchange audio, video, and arbitrary data directly, without a server in the path. Google open-sourced the original project in 2011, and standardization proceeded on two fronts, the W3C for the browser-facing JavaScript API and the IETF for the underlying protocols, culminating in 2021 with the W3C's WebRTC 1.0 recommendation and a family of IETF RFCs starting with RFC 8825. Before WebRTC, real-time audio and video in the browser required Flash, native app SDKs, or dedicated plugins; WebRTC made P2P real-time communication possible with nothing more than an open browser tab.
The core achievement of WebRTC is packaging everything a browser sandbox otherwise makes hard (signaling, NAT traversal, encryption, congestion control, media codecs) into a single standardized API surface. Developers work with one object, RTCPeerConnection, without needing to reason directly about the ICE, STUN/TURN, DTLS, SRTP, and SCTP machinery running underneath it.
Building blocks
- RTCPeerConnection
- The central WebRTC API. It represents a connection to a single peer and is where nearly everything happens: adding media tracks and data channels, collecting ICE candidates, and generating and applying SDP offers and answers.
- MediaStream (getUserMedia)
- Audio and video captured from devices via
navigator.mediaDevices.getUserMedia(). Tracks from the resulting stream are added to anRTCPeerConnectionso they can be sent directly to the remote peer.getDisplayMedia()is the sibling API used for screen sharing. - RTCDataChannel
- A bidirectional channel for arbitrary, non-media data. Under the hood it runs SCTP (Stream Control Transmission Protocol) over DTLS. It supports a TCP-like mode with guaranteed reliability and ordering, but also lower-latency, UDP-like modes selectable via options such as
orderedandmaxRetransmits. - ICE (Interactive Connectivity Establishment)
- The framework (RFC 8445) that finds a working path between two peers. Each side gathers a set of candidate paths, the candidates are exchanged, connectivity checks are run against them, and the best working pair is selected.
- SDP (Session Description Protocol)
- A text format (RFC 8866) describing the media session about to be established: codecs, media types, encryption parameters, ICE candidates, and so on. WebRTC reaches agreement on a session through a single round of SDP exchange known as the offer/answer.
How a connection is established
- Signaling: the stage where the two peers exchange SDP offers/answers and ICE candidates. Crucially, the WebRTC specification does not define how signaling is transported; it only needs the SDP to arrive somehow. In practice this is usually done through a WebSocket server or messaging service, meaning that although the media and data themselves flow P2P, some kind of server is still needed to play matchmaker for the connection (the next section covers signaling approaches in detail).
- ICE candidate gathering: each peer collects the paths it might be reachable through. These fall into three broad categories: host candidates (addresses of local network interfaces), server reflexive candidates (the peer's public-facing address as reported by a STUN server), and relay candidates (a relay point reached through a TURN server, used when direct connectivity is not possible).
- NAT traversal via STUN/TURN: a STUN server does nothing more than tell a client how it looks from the outside; combined with UDP hole punching, this is enough to open a direct path through most NAT configurations. When direct connectivity genuinely cannot be established (symmetric NATs being the classic case), a TURN server acts as a last-resort relay, forwarding packets between the two peers.
- DTLS handshake: once a working path is selected, a DTLS (Datagram TLS) handshake runs over it to exchange keys and authenticate both sides.
- Media and data flow: over the now-encrypted path, audio and video travel as SRTP (Secure RTP) and arbitrary data travels as SCTP. All subsequent traffic passes through this encrypted tunnel.
To be precise: WebRTC is P2P, but it is not serverless. Signaling always requires some server (or at least an existing communication channel), and most deployments also stand up a STUN server plus a TURN server as a fallback for when direct connectivity fails. Cases where a direct path simply cannot be opened (symmetric NATs paired with restrictive firewalls, for instance) are common enough in practice that TURN-relayed traffic is effectively routed through a server anyway. What WebRTC provides is a design that tries direct connectivity first and falls back to relaying, not a mechanism that eliminates servers altogether.
Signaling in detail
WebRTC negotiation follows the JSEP model (JavaScript Session Establishment Protocol, RFC 8829), which deliberately stays agnostic about transport: the only requirement is that SDP offers/answers and ICE candidates somehow reach the other peer. Whether that happens over a WebSocket, an HTTP request, email, or manual copy-paste is left undefined by the spec. This freedom is what enables such a wide range of implementations, but it also means one design decision, when and how ICE candidates are exchanged, ends up dramatically changing both connection-setup speed and implementation complexity.
Non-Trickle ICE (Vanilla ICE)
The most straightforward approach. After calling setLocalDescription(), the peer waits until ICE candidate gathering has fully completed, then exchanges a single, complete SDP that already contains every candidate. The advantage is that signaling collapses to one round trip, one offer and one answer, so it works over channels with no real-time capability at all, such as a single HTTP request, a QR code, or manual copy-paste. The drawback is that gathering involves enumerating network interfaces, querying STUN servers, and requesting TURN allocations, and this can take several seconds, for instance while waiting out timeouts against an unresponsive server, during which the user simply waits with nothing happening. This makes Non-Trickle ICE a poor fit whenever perceived connection speed matters.
Trickle ICE
Trickle ICE (RFC 8838) takes the opposite approach: rather than waiting for gathering to finish, the SDP is sent immediately with zero or few candidates, and each additional candidate is "trickled" over the signaling channel as it is discovered via the onicecandidate event. The receiving side adds candidates as they arrive with addIceCandidate() and can begin connectivity checks the moment the first candidates land. SDP exchange, candidate gathering, and connectivity checks all proceed in parallel, substantially cutting connection-establishment time compared to Non-Trickle ICE. Browsers' WebRTC implementations use Trickle ICE by default. The prerequisite is a bidirectional, low-latency signaling channel capable of carrying candidates as they appear; a WebSocket connection is the typical choice. Both ends need to support trickling for the full benefit, but compatibility degrades gracefully: an endpoint can fall back to non-trickle behavior toward a peer that doesn't support it.
WHIP / WHEP: standardized HTTP signaling
The flip side of signaling freedom is fragmentation: every service ended up inventing its own protocol, leaving broadcast hardware and software with no interoperability. The IETF's answer is WHIP (WebRTC-HTTP Ingestion Protocol, RFC 9725), which exchanges SDP in a single HTTP round trip. WHIP targets the ingest side, where an encoder such as OBS "pushes" media to a media server: POST the SDP offer, receive the answer in the response, done. Its egress counterpart for viewers, WHEP (WebRTC-HTTP Egress Protocol), is still moving through standardization. The motivation is to replace RTMP for live-stream ingest with sub-second-latency WebRTC. The base flow is essentially Non-Trickle (one round trip), but Trickle ICE and ICE restarts delivered via HTTP PATCH are specified as options on top of it. With OBS Studio and major CDNs and media servers shipping support, WHIP is establishing itself as "RTMP for the WebRTC era."
| Aspect | Non-Trickle (Vanilla) | Trickle ICE | WHIP/WHEP |
|---|---|---|---|
| SDP exchange | Single complete offer/answer, sent once gathering finishes | Offer/answer sent early, candidates trickle in afterward | Single HTTP round trip (offer in the request, answer in the response) |
| How candidates are sent | Bundled inside the one SDP exchange | Streamed individually via onicecandidate/addIceCandidate as they're discovered | Bundled in the initial exchange; trickling and restarts optionally added via HTTP PATCH |
| Connection-setup speed | Slow: blocked on full gathering, up to several seconds | Fast: gathering, exchange, and checks run in parallel | Fast for ingest: one HTTP call, no waiting on a persistent channel |
| Channel requirements | Any channel, even one-shot (HTTP request, QR code, copy-paste) | Bidirectional, low-latency, real-time channel (typically WebSocket) | Plain HTTP; no persistent connection needed for the base flow |
| Typical use | Simple one-off exchanges where speed doesn't matter | Browser-to-browser calls and conferencing, where fast connect matters | Encoder-to-server live-stream ingest (and, via WHEP, egress to viewers) |
Mesh signaling: toward serverless signaling
Once a P2P mesh has grown past its first few members, established P2P connections can themselves carry signaling for new ones: a node already in the mesh acts as an intermediary, relaying SDP/ICE exchanges with a joining peer over an existing data channel instead of routing everything back through the signaling server. Load on the signaling server drops, and the mesh becomes more resilient to that server going down mid-session.
The chicken-and-egg constraint remains, though: a brand-new participant with zero connections still needs some external bootstrap, such as a server, a relay, or a pre-existing channel, to establish its very first connection. P2P signaling only helps once the network already exists; it cannot be the thing that gets the very first peer in.
A further variant replaces the dedicated signaling server entirely with a general-purpose pub/sub relay such as Nostr as the signaling transport. The standard privacy design in that setup: sign signaling traffic with disposable ephemeral keys decoupled from the application's persistent identity, and keep the real identity only inside encrypted payloads, hidden even from the relay operator itself.
Security
Both media and data channels are mandatorily encrypted in WebRTC: the specification simply does not offer an unencrypted option. Session keys are exchanged over DTLS, and from that point on, audio and video travel as SRTP while data channels travel as SCTP over DTLS; unencrypted transmission is never on the table.
- IP-address exposure: during ICE candidate gathering, the browser generates candidates that reveal a private local-network IP address and, via the STUN request, a public IP address as seen from the internet. This mechanism gave rise to the well-known "WebRTC IP leak," where a user's real IP address could be exposed even while connected through a VPN.
- Mitigation via mDNS candidates: current major browsers mitigate this by default, replacing the raw local host candidate's IP address with a randomized
.localmDNS hostname before sharing it. This preserves connectivity within the same local network while keeping the private IP address hidden from unrelated third parties.
The limits of topology: from full mesh to SFU/MCU
For a one-on-one call, a full mesh where the two peers connect directly works perfectly well. But once a video call grows to n participants and everyone tries to maintain a full mesh, each peer has to keep n-1 connections alive and keep uploading its own audio and video n-1 times over. Connection count grows as O(n²), and any individual client's upload bandwidth and processing power become the bottleneck at a surprisingly small number of participants: full mesh simply does not scale past small group calls.
The practical answer to this limit is reintroducing a centralized server in the form of an SFU (Selective Forwarding Unit) or an MCU (Multipoint Control Unit). An SFU is essentially a router: it receives each participant's media stream and forwards it, undecoded, to the other participants, so each client only needs to sustain one upload and the equivalent of (n-1) downloads. An MCU goes a step further, mixing and compositing everyone's audio and video on the server side into a single combined stream, further reducing the client-side load at the cost of significant server-side compute. Many video conferencing services, Google Meet, Discord, and Zoom's browser client among them, use the SFU model. This is a direct trade-off between the P2P ideal and practical scalability for many participants, and the same tension resurfaces in the multi-party scalability challenges discussed in P2P and the metaverse.
Applications
- Video conferencing and voice calls: services such as Google Meet, Discord, and the browser client of Zoom use WebRTC as their media-transport foundation.
- File transfer: RTCDataChannel lets browsers send files directly to one another without routing through a server first.
- P2P networks in the browser: RTCDataChannel is not media-specific; it is a general-purpose P2P pipe for arbitrary binary data. Built on top of it, WebTorrent lets a browser join a BitTorrent-style swarm directly, while browser-based IPFS nodes and libp2p's WebRTC transport turn a browser into a first-class P2P network participant with no dedicated app to install. The significance is that browsers, previously limited to downloading from servers, can now upload as full peers too.
Comparing WebSocket, WebTransport, and WebRTC DataChannel
| Aspect | WebSocket | WebTransport | WebRTC DataChannel |
|---|---|---|---|
| Connection shape | Client–server (always 1:1, server required) | Client–server (always 1:1, server required) | Peer-to-peer (server only assists with signaling and NAT traversal) |
| Transport | TCP | QUIC (UDP-based) | SCTP over DTLS (UDP-based) |
| Reliability and ordering | Fixed to TCP semantics: always reliable and ordered | Selectable per stream; datagrams are unreliable | Flexible per stream via options such as ordered and maxRetransmits |
| Signaling required | No: just connect to a URL | No: just connect to a URL | Yes: SDP/ICE candidates must be exchanged beforehand |
| Typical use | General real-time client–server communication (chat, notifications) | Low-latency server communication, media streaming, multiplexed datagram transfer | Video-conferencing audio/video/chat, P2P file transfer, browser-based P2P networks |
Related pages
The foundation WebRTC relies on for direct connectivity is exactly the STUN/TURN/ICE machinery covered in NAT traversal, and signaling is commonly implemented over WebSocket. The scalability problems that surface with many participants connect directly to the concurrency challenges discussed in P2P and the metaverse, and browser-based P2P networks built on RTCDataChannel, like WebTorrent, directly inherit the swarm mechanics of BitTorrent. The SFU/cascade split introduced here for group calls is also exactly the topology P2P live streaming builds on to fan a broadcast out to a large audience. When all you need is simple bidirectional communication with a server, WebRTC's complexity is unnecessary; see WebSocket and WebTransport for lighter-weight alternatives.