Frontend / Browser internals / 07_webrtc_and_webtransport.md

WebRTC and WebTransport

Updated 5 interview angles 7 min read source
On this page6
  1. WebRTC
  2. WebTransport
  3. Gotchas
  4. Related
  5. Further reading
  6. Interview angle

WebRTC and WebTransport

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).

text
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 B

After 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:

js
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.

ts
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.

ts
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.

ts
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

  • 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 — getUserMedia requires 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.

Further reading

Interview angle 5

  • “What does WebRTC give you, and what do you still have to build?” - encrypted peer-to-peer audio, video and data between browsers. Signalling is yours: the specification deliberately does not say how two peers find each other, so you provide the channel that exchanges offers, answers and ICE candidates. NAT traversal itself is handled by ICE with STUN and TURN.
  • “What is TURN, and why does it matter commercially?” - the relay fallback when a direct peer connection cannot be established, which is a meaningful fraction of real connections. It relays all the media through your infrastructure, so it is the expensive part of the bill and needs budgeting rather than treating as a rare edge case.
  • “How far does a mesh scale?” - three or four peers. Every participant sends their stream to every other, so upstream bandwidth grows with the group and consumer connections give out first. Past that you need an SFU, which receives each stream once and forwards it.
  • “Would you use the raw API?” - no. It is verbose and full of edge cases around renegotiation, track handling and device changes, so a library or a hosted platform is the normal answer unless the protocol itself is your product.
  • “What is WebTransport for?” - HTTP/3-based transport with multiple independent streams and unreliable datagrams, so it avoids the head-of-line blocking a single ordered WebSocket has. Support is still uneven, so WebSockets remain the default and WebTransport is the answer when one ordered stream is genuinely the constraint.