WebRTC and WebTransport
TL;DR
Two transport APIs beyond WebSocket. WebRTC is peer-to-peer real-time — video/audio/data between browsers without a server in the middle (after signaling). The senior knowledge: STUN/TURN/ICE for NAT traversal, signaling is your problem (not standardized), RTCPeerConnection for streams, RTCDataChannel for arbitrary data. WebTransport (newer) is a server-client low-latency transport over HTTP/3 — alternative to WebSocket with multiple streams, datagrams, no head-of-line blocking. Mostly senior trivia / for system design rounds; rarely used directly in app code.
WebRTC
What’s WebRTC for?
Peer-to-peer, low-latency audio/video/data in the browser. Use cases:
- Video calls (Zoom-like, Jitsi, Google Meet uses WebRTC).
- Voice chat / Discord-style.
- Screen sharing.
- File transfer (P2P, no server bandwidth).
- Multiplayer games (data channel for state).
- Collab features (Figma’s cursor presence uses WebRTC over data channel in some setups).
The killer feature: direct browser-to-browser, not relayed through your server (most of the time). Lower latency, no server bandwidth cost for media.
The signaling problem.
WebRTC needs the peers to exchange connection info (ICE candidates, SDP offers/answers) before they can connect directly. This exchange is not standardized — you provide a signaling channel (WebSocket, HTTP, anything).
Peer A ───(SDP offer)──→ your signaling server ───(SDP offer)──→ Peer B
Peer A ←──(SDP answer)── your signaling server ←──(SDP answer)── Peer B
Peer A ──(ICE candidates)→→→... ←←← Peer BAfter signaling completes, peers connect directly. Signaling is “out of band” — it’s your code, typically a WebSocket server that relays messages between peers.
ICE, STUN, TURN — what each does.
NAT traversal infrastructure:
| What | |
|---|---|
| ICE (Interactive Connectivity Establishment) | the framework — gather candidate addresses, try them in priority order until one works |
| STUN | “what’s my public IP and port?” — lightweight server tells the peer its NAT-translated address. Free; many public servers (e.g., Google’s). |
| TURN | full relay through a server when peer-to-peer fails (~10-20% of cases — symmetric NAT, restrictive firewalls). Expensive to host (uses your bandwidth). |
A real app config:
const pc = new RTCPeerConnection({
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "turn:your.turn.server:3478", username: "x", credential: "y" },
],
});Without TURN: ~80% of calls connect P2P, ~20% fail. With TURN: ~100% connect (some through relay). TURN bandwidth costs are why hosted services charge per minute.
RTCPeerConnection setup flow.
const pc = new RTCPeerConnection({ iceServers: [...] });
// Local side: get media, add tracks
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// Remote side: handle incoming streams
pc.ontrack = (e) => {
remoteVideoEl.srcObject = e.streams[0];
};
// ICE candidates as they're discovered
pc.onicecandidate = (e) => {
if (e.candidate) signaling.send({ type: "ice", candidate: e.candidate });
};
// Caller: create offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
signaling.send({ type: "offer", sdp: offer });
// Callee: receive offer, create answer
async function onOffer(offerSdp) {
await pc.setRemoteDescription(offerSdp);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
signaling.send({ type: "answer", sdp: answer });
}
// Both sides: handle incoming ICE candidates
async function onIce(candidate) {
await pc.addIceCandidate(candidate);
}Verbose. Libraries like simple-peer, PeerJS, or full SDKs (LiveKit, Agora, Twilio) hide most of this.
RTCDataChannel — arbitrary data without media.
const channel = pc.createDataChannel("chat", { ordered: true });
channel.onopen = () => channel.send("hello");
channel.onmessage = (e) => console.log("got", e.data);
// Receiver
pc.ondatachannel = (e) => {
const channel = e.channel;
channel.onmessage = (e) => console.log("received", e.data);
};Options:
ordered: true(default) — packets arrive in order. Like TCP.ordered: false, maxRetransmits: 0— fire and forget. Like UDP. For game state.maxRetransmits/maxPacketLifeTime— bounded reliability.
Use for: real-time game state, collaborative cursors (Figma’s presence), file transfer (P2P), arbitrary low-latency messages.
Selective Forwarding Unit (SFU) — when peer-to-peer breaks down.
Pure mesh WebRTC doesn’t scale — 10 peers in a call means each uploads 9 streams (10×9 connections). At ~500 KB/s per stream, that’s 4.5 MB/s upload per peer — too much.
SFU is a server that receives one upload from each peer and forwards to others. Each peer uploads once (to the SFU), receives N streams. Bandwidth is server-side, not P2P.
MCU (Multipoint Control Unit) — older approach; server mixes streams into one and re-encodes. Heavier CPU, easier client.
Real video-conference apps (Zoom, Meet) use SFUs/MCUs, not pure P2P, beyond ~3-4 participants.
WebRTC libraries serving this: mediasoup, Janus, LiveKit, Jitsi Videobridge.
Security — is WebRTC encrypted?
Yes. WebRTC media and data is always DTLS-SRTP encrypted (DTLS for the data, SRTP for media). No opt-out. Even peer-to-peer with no server, the data is encrypted between peers.
Caveat: end-to-end encrypted means peer-to-peer, but a SFU is on the path — it sees the encrypted streams but in some products terminates and re-encrypts (so “E2EE” needs Insertable Streams or similar to be true end-to-end).
When use WebRTC vs WebSocket?
| Use WebRTC | Use WebSocket |
|---|---|
| audio/video streams | text messaging |
| low-latency game data | server pushes (notifications) |
| direct peer-to-peer (file transfer, cursor sync) | server is the source of truth |
| huge throughput (avoiding server bandwidth) | request/response-like |
For server-mediated chat / collab where the server is canonical, WebSocket is simpler. For peer-to-peer / media / extreme latency / massive throughput, WebRTC.
WebTransport
What’s WebTransport?
A newer transport API (Chrome 97+) for bidirectional client-server communication over HTTP/3. Designed as a more capable WebSocket replacement.
const transport = new WebTransport("https://example.com:4433/path");
await transport.ready;
// Reliable, ordered, bidirectional stream
const stream = await transport.createBidirectionalStream();
const writer = stream.writable.getWriter();
const reader = stream.readable.getReader();
await writer.write(encoder.encode("hello"));
const { value, done } = await reader.read();
// Unreliable datagrams (UDP-like)
const dgramWriter = transport.datagrams.writable.getWriter();
await dgramWriter.write(encoder.encode("packet"));
for await (const dgram of transport.datagrams.readable) {
// received datagram
}Advantages over WebSocket:
- Multiple streams — no head-of-line blocking between streams.
- Datagrams — UDP-like, no retransmission, lowest latency.
- HTTP/3 / QUIC — multiplexed, encrypted, 0-RTT, connection migration.
- Backpressure built-in via streams API.
Disadvantages:
- Newer, less broadly supported — Chrome + Edge + Firefox (rolling out); not Safari (as of 2024-2025).
- Server support is also rolling out — needs a QUIC-capable server (some Node frameworks, Cloudflare Workers, custom).
- More complex API than WebSocket.
When use WebTransport vs WebSocket?
Use WebTransport when:
- You need multiple independent streams (no HOL blocking between them).
- You need unreliable datagrams (game state, voice/video metadata).
- You’re already on HTTP/3 infrastructure.
Use WebSocket when:
- Broad browser support matters (everywhere).
- Single ordered stream is enough.
- Familiar tooling / debugging.
For 2026 most apps: WebSocket is still the right default. WebTransport for niche performance-critical use cases (games, real-time audio metadata, edge networking).
WebTransport vs WebRTC data channels?
| WebTransport | WebRTC DataChannel | |
|---|---|---|
| Topology | server-client | peer-to-peer |
| Transport | HTTP/3 (QUIC) | DTLS/SCTP over UDP |
| Setup | URL → connect | signaling → ICE → DTLS handshake |
| Use | server-mediated streams | P2P data |
DataChannel = peer-to-peer; WebTransport = server-mediated. Different shapes; pick by topology.
Gotchas / edge cases
- WebRTC signaling is your responsibility — not built into the API. Plan it (WebSocket, HTTP polling, anything).
- TURN bandwidth is expensive — hosted TURN providers (Twilio, coturn) cost per GB. Account for it in pricing models.
- WebRTC + corporate networks — many block UDP. TURN fallback over TCP/443 is essential.
- Browser permissions —
getUserMediarequires HTTPS + user gesture; permission must be granted explicitly. - WebRTC API churn — older Promise vs callback variants; verify against modern docs.
- WebTransport URL must be HTTPS + QUIC-capable server — fails silently if the server doesn’t support HTTP/3.
- Datagrams aren’t reliable — packets can be lost or reordered. Implement application-level reliability if needed.
- Streams are not FIFO across multiple streams — each stream is ordered; streams relative to each other are not.
What a senior is expected to say 6
- “WebRTC is peer-to-peer real-time — audio/video/data between browsers, encrypted by default. Signaling (how peers find each other) is your problem; ICE/STUN/TURN handle NAT traversal.”
- “TURN is the relay fallback when P2P fails — ~10-20% of cases. Bandwidth-expensive; budget for it.”
- “Pure mesh WebRTC doesn’t scale past 3-4 peers — use an SFU (Selective Forwarding Unit) for video conferences.”
- “Use libraries (simple-peer, LiveKit, Agora) rather than hand-rolling — the raw API is verbose and full of edge cases.”
- “WebTransport is the newer HTTP/3-based alternative to WebSocket — multiple streams, datagrams, no HOL blocking. Not yet broadly supported; WebSocket is still the default.”
- “RTCDataChannel for arbitrary P2P data (game state, cursors, file transfer); WebTransport for server-mediated streams when WebSocket’s single ordered stream isn’t enough.”
Cross-references
- WebSocket (the simpler default): WebSockets — Integration, Reconnection, and Real-Time UX
- Server-side chat & presence (often signaling is a WebSocket): Worked Design — Chat & Presence
- HTTP/3 + QUIC (what WebTransport runs on): HTTP Versions — 1.0, 1.1, 2, 3
Further reading
- MDN — WebRTC API: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API
- MDN — WebTransport: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API
- WebRTC samples (canonical reference): https://webrtc.github.io/samples/
- LiveKit (modern WebRTC SFU): https://livekit.io/
- W3C WebTransport spec: https://www.w3.org/TR/webtransport/