What is WebRTC?
WebRTC (Web Real-Time Communication) is an open-source technology that enables peer-to-peer audio, video, and data sharing directly between browsers and mobile apps without requiring plugins or intermediary servers.
The magic: Your browser talks directly to your friend's browser, not through a server.
Why P2P? The Latency Problem
Traditional streaming (Client → Server → Client): You → YouTube Server → Friend Latency: 5-30 seconds (buffering, processing) WebRTC (Peer-to-Peer): You → Friend (direct connection) Latency: 50-300ms (near real-time) Use cases: Video calls, live gaming, screen sharing
Comparison
| Feature | Traditional Streaming | WebRTC P2P |
|---|---|---|
| Latency | 5-30 seconds | 50-300ms |
| Server Cost | High (relay all traffic) | Low (signaling only) |
| Quality | Buffered, stable | Real-time, adaptive |
| Use Case | YouTube, Netflix | Zoom, Discord, Gaming |
Core Components
WebRTC has 3 main APIs:
1. MediaStream (getUserMedia)
Access camera and microphone.
// Get video and audio from user's device
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: 1280, height: 720 },
audio: true
});
// Display on page
const videoElement = document.querySelector('video');
videoElement.srcObject = stream;
2. RTCPeerConnection
Create peer-to-peer connection.
// Create connection
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
// Add local stream
stream.getTracks().forEach(track => {
peerConnection.addTrack(track, stream);
});
// Receive remote stream
peerConnection.ontrack = (event) => {
remoteVideo.srcObject = event.streams[0];
};
3. RTCDataChannel
Send arbitrary data peer-to-peer.
// Create data channel
const dataChannel = peerConnection.createDataChannel('chat');
dataChannel.onopen = () => {
dataChannel.send('Hello!');
};
dataChannel.onmessage = (event) => {
console.log('Received:', event.data);
};
The NAT Problem
Problem: Most devices don't have public IP addresses. They're behind routers with NAT (Network Address Translation).
Your Computer: 192.168.1.5 (private IP)
↓
Router NAT
↓
ISP: 203.0.113.42 (public IP)
Challenge: Friend can't connect to 192.168.1.5 directly. They need your public IP and port.
NAT Traversal: STUN, TURN, ICE
STUN Server (Session Traversal Utilities for NAT)
"Mirror" server that tells you your public IP and port.
const config = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' }
]
};
const pc = new RTCPeerConnection(config);
How it works:
You → STUN Server: "What's my public address?" STUN → You: "You are 203.0.113.42:54321" You → Friend: "Connect to me at 203.0.113.42:54321"
TURN Server (Traversal Using Relays around NAT)
Relay server when direct P2P fails (e.g., strict corporate firewalls).
const config = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{
urls: 'turn:turn.example.com:3478',
username: 'user',
credential: 'password'
}
]
};
When needed:
Symmetric NAT or Strict Firewall:
You ← Can't connect directly → Friend
↓ ↓
TURN Server (relay)
You → TURN → Friend
(Slower, but works)
Cost: TURN servers relay all media traffic = expensive bandwidth
ICE (Interactive Connectivity Establishment)
Protocol that tries multiple connection methods, picking the best.
ICE candidates (in order of preference): 1. Host candidate: Direct LAN connection (192.168.x.x) 2. Server reflexive: STUN-discovered public IP (P2P via router) 3. Relay candidate: TURN server relay (fallback) ICE tries all candidates, uses fastest successful connection
WebRTC Connection Flow
sequenceDiagram
participant A as Alice
participant S as Signaling Server
participant B as Bob
A->>A: getUserMedia()
A->>A: createOffer()
A->>S: Send offer (SDP)
S->>B: Forward offer
B->>B: setRemoteDescription(offer)
B->>B: createAnswer()
B->>S: Send answer (SDP)
S->>A: Forward answer
A->>A: setRemoteDescription(answer)
Note over A,B: ICE Candidates Exchange
A->>S: ICE candidate
S->>B: Forward candidate
B->>S: ICE candidate
S->>A: Forward candidate
Note over A,B: P2P Connection Established!
A->>B: Media stream (direct P2P)
Step-by-Step
- Get media: Both users grant camera/mic access
- Create offer: Alice creates SDP offer describing her capabilities
- Signal offer: Alice sends offer to Bob via signaling server (WebSocket)
- Create answer: Bob creates SDP answer
- Signal answer: Bob sends answer to Alice
- ICE candidates: Both exchange network information
- Connect: WebRTC establishes best possible connection
- Stream: Media flows peer-to-peer
Complete Implementation
Signaling Server (Node.js + Socket.IO)
// server.js
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
const rooms = new Map();
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
socket.on('join-room', (roomId) => {
socket.join(roomId);
// Notify others in room
socket.to(roomId).emit('user-joined', socket.id);
});
// Forward WebRTC signaling messages
socket.on('offer', (data) => {
socket.to(data.target).emit('offer', {
offer: data.offer,
sender: socket.id
});
});
socket.on('answer', (data) => {
socket.to(data.target).emit('answer', {
answer: data.answer,
sender: socket.id
});
});
socket.on('ice-candidate', (data) => {
socket.to(data.target).emit('ice-candidate', {
candidate: data.candidate,
sender: socket.id
});
});
socket.on('disconnect', () => {
socket.broadcast.emit('user-left', socket.id);
});
});
server.listen(3000);
Client (JavaScript)
// client.js
const socket = io('http://localhost:3000');
const roomId = 'room123';
const config = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' }
]
};
let localStream;
let peerConnections = {};
// Get local media
async function startCall() {
localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
document.getElementById('localVideo').srcObject = localStream;
socket.emit('join-room', roomId);
}
// Create peer connection
function createPeerConnection(peerId) {
const pc = new RTCPeerConnection(config);
// Add local stream
localStream.getTracks().forEach(track => {
pc.addTrack(track, localStream);
});
// Handle remote stream
pc.ontrack = (event) => {
const remoteVideo = document.getElementById(`remote-${peerId}`);
remoteVideo.srcObject = event.streams[0];
};
// Handle ICE candidates
pc.onicecandidate = (event) => {
if (event.candidate) {
socket.emit('ice-candidate', {
target: peerId,
candidate: event.candidate
});
}
};
peerConnections[peerId] = pc;
return pc;
}
// User joined room
socket.on('user-joined', async (peerId) => {
const pc = createPeerConnection(peerId);
// Create and send offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit('offer', {
target: peerId,
offer: offer
});
});
// Receive offer
socket.on('offer', async ({ offer, sender }) => {
const pc = createPeerConnection(sender);
await pc.setRemoteDescription(new RTCSessionDescription(offer));
// Create and send answer
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
socket.emit('answer', {
target: sender,
answer: answer
});
});
// Receive answer
socket.on('answer', async ({ answer, sender }) => {
const pc = peerConnections[sender];
await pc.setRemoteDescription(new RTCSessionDescription(answer));
});
// Receive ICE candidate
socket.on('ice-candidate', async ({ candidate, sender }) => {
const pc = peerConnections[sender];
await pc.addIceCandidate(new RTCIceCandidate(candidate));
});
// User left
socket.on('user-left', (peerId) => {
if (peerConnections[peerId]) {
peerConnections[peerId].close();
delete peerConnections[peerId];
}
});
Protocols & Codecs
Transport Protocols
UDP (User Datagram Protocol): - Connectionless, unreliable - Fast, low latency - Preferred for WebRTC (video/audio) - Drops packets instead of retransmitting TCP (Transmission Control Protocol): - Connection-oriented, reliable - Slower, higher latency - Fallback for DataChannel
Media Protocols
RTP (Real-time Transport Protocol): - Delivers audio/video packets - Timestamps and sequence numbers - No encryption SRTP (Secure RTP): - Encrypted version of RTP - Used by WebRTC - Prevents eavesdropping RTCP (RTP Control Protocol): - Quality metrics and feedback - Packet loss, jitter, round-trip time
Video Codecs
// Check supported codecs
RTCRtpReceiver.getCapabilities('video').codecs.forEach(codec => {
console.log(codec.mimeType);
});
// Common codecs:
VP8: Open source, good quality, lower CPU
VP9: Better compression, higher CPU
H.264: Patent-encumbered, hardware accelerated, universal
AV1: Next-gen, best compression, experimental
Real-World Applications
1. Zoom / Google Meet
// Multi-party video conferencing
// Each participant P2P with server for mixing
Participant A ←→ Media Server ←→ Participant B
↕
Participant C
// Server mixes streams (SFU - Selective Forwarding Unit)
2. Discord Voice Channels
// Voice chat with low latency
const dataChannel = pc.createDataChannel('voice', {
ordered: false, // Don't wait for missing packets
maxRetransmits: 0 // Don't retransmit
});
3. Screen Sharing
// Capture screen instead of camera
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: { cursor: 'always' },
audio: false
});
peerConnection.addTrack(screenStream.getVideoTracks()[0]);
4. File Transfer (P2P)
// Send large files directly without server
const dataChannel = pc.createDataChannel('file-transfer');
const CHUNK_SIZE = 16384; // 16KB chunks
function sendFile(file) {
const reader = new FileReader();
let offset = 0;
reader.onload = (e) => {
dataChannel.send(e.target.result);
offset += e.target.result.byteLength;
if (offset < file.size) {
readSlice(offset);
}
};
const readSlice = (o) => {
const slice = file.slice(offset, o + CHUNK_SIZE);
reader.readAsArrayBuffer(slice);
};
readSlice(0);
}
Scaling Challenges
Mesh (Full P2P)
3 participants: 3 connections A ←→ B A ←→ C B ←→ C 10 participants: 45 connections! Each user uploads to 9 others = 9x bandwidth
Limitation: Doesn't scale beyond ~5 participants
SFU (Selective Forwarding Unit)
Server forwards streams without mixing A → SFU → B, C, D B → SFU → A, C, D C → SFU → A, B, D Each client uploads 1 stream, downloads N-1 streams Server load: Linear with participants
Used by: Zoom, Google Meet, Discord
MCU (Multipoint Control Unit)
Server mixes all streams into one A, B, C → MCU (mixes) → Composed stream → A, B, C Each client uploads 1, downloads 1 Server load: High (CPU encoding)
Interview Tips
When discussing WebRTC in system design interviews:
- Explain P2P benefit: "Direct connection reduces latency to <300ms vs 5-30s for server relay..."
- NAT traversal: "We'd use STUN for most users, TURN relay as fallback for strict firewalls..."
- Signaling server: "Need WebSocket server for SDP offer/answer exchange, not for media..."
- Scaling: "For >5 users, implement SFU server to forward streams without mixing..."
- Fallback: "If WebRTC fails, fallback to traditional RTMP streaming..."
- Real examples: "Zoom uses WebRTC with SFU for scalability..."
Related Concepts
- WebSockets — Used for WebRTC signaling
- UDP vs TCP — Transport protocol trade-offs
- CDN — Deliver TURN servers from edge locations
- Load Balancing — Distribute SFU server load
- Video Encoding — Codec selection and optimization
About ScaleWiki
ScaleWiki is an interactive educational platform dedicated to demystifying distributed systems, software architecture, and system design. Our mission is to provide high-quality, technically accurate resources for software engineers preparing for interviews or solving complex scaling challenges in production.
Read more about our Editorial Guidelines & Authorship.
Educational Disclaimer: The architectural patterns and system designs discussed in this article are based on common industry practices, technical whitepapers, and public engineering blogs. Actual implementations in enterprise environments may vary significantly based on specific product requirements, legacy constraints, and evolving technologies.
Related Articles
DNS Architecture
The phonebook of the internet. How Domain Name System works, the hierarchy of Route 53, and recursive vs iterative resolution strategies.
HTTP Evolution (H1 to H3)
From text-based HTTP/1.1 to binary HTTP/2 and UDP-based HTTP/3 (QUIC). Why we needed upgrades and how they solve Head-of-Line Blocking.
TCP Handshake & Congestion
The 3-way handshake that powers the internet. SYN, SYN-ACK, ACK. Flow control vs Congestion control, and modern algorithms like BBR.