Back to All Concepts
NetworkingProtocolsReal-timeAdvanced

WebRTC (Peer-to-Peer Communication)

Web Real-Time Communication protocol enabling direct peer-to-peer audio, video, and data transfer between browsers without intermediary servers, powering low-latency applications like Zoom and Google Meet.

Last updated: By the ScaleWiki Editorial Team

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

FeatureTraditional StreamingWebRTC P2P
Latency5-30 seconds50-300ms
Server CostHigh (relay all traffic)Low (signaling only)
QualityBuffered, stableReal-time, adaptive
Use CaseYouTube, NetflixZoom, Discord, Gaming

Core Components

WebRTC has 3 main APIs:

1. MediaStream (getUserMedia)

Access camera and microphone.

javascript
// 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.

javascript
// 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];
};
Click to expand code...

3. RTCDataChannel

Send arbitrary data peer-to-peer.

javascript
// 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.

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

javascript
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

Step-by-Step

  1. Get media: Both users grant camera/mic access
  2. Create offer: Alice creates SDP offer describing her capabilities
  3. Signal offer: Alice sends offer to Bob via signaling server (WebSocket)
  4. Create answer: Bob creates SDP answer
  5. Signal answer: Bob sends answer to Alice
  6. ICE candidates: Both exchange network information
  7. Connect: WebRTC establishes best possible connection
  8. Stream: Media flows peer-to-peer

Complete Implementation

Signaling Server (Node.js + Socket.IO)

javascript
// 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);
Click to expand code...

Client (JavaScript)

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];
  }
});
Click to expand code...

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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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)

javascript
// 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);
}
Click to expand code...

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:

  1. Explain P2P benefit: "Direct connection reduces latency to <300ms vs 5-30s for server relay..."
  2. NAT traversal: "We'd use STUN for most users, TURN relay as fallback for strict firewalls..."
  3. Signaling server: "Need WebSocket server for SDP offer/answer exchange, not for media..."
  4. Scaling: "For >5 users, implement SFU server to forward streams without mixing..."
  5. Fallback: "If WebRTC fails, fallback to traditional RTMP streaming..."
  6. 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