WebRTC Cheatsheet
WebRTC Basics
Use this WebRTC reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What WebRTC Is
WebRTC (Web Real-Time Communication) is a browser API for peer-to-peer audio, video, and data without plugins. Three core APIs cover everything:
| API | Purpose |
|---|---|
getUserMedia() / getDisplayMedia() | Capture mic, camera, or screen |
RTCPeerConnection | Establish and manage a P2P connection |
RTCDataChannel | Send arbitrary binary/text data peer-to-peer |
WebRTC is not a standalone protocol — it requires a signaling channel (WebSocket, HTTP, etc.) you build yourself to exchange session descriptions and ICE candidates before the P2P link forms.
Core Concepts
The Connection Lifecycle (always in this order)
- Capture local media (
getUserMedia) - Create
RTCPeerConnectionwith ICE server config - Add tracks / create data channels
- Create offer (caller) or answer (callee) — SDP
- Exchange SDP and ICE candidates via your signaling channel
- Connection negotiates,
iceConnectionState→"connected"
SDP — Session Description Protocol
SDP is a text blob that describes codecs, bandwidth, encryption fingerprints, and media directions. You never hand-parse it; pass it opaquely between peers.
// SDP looks like: // v=0 // o=- 4611731400430051336 2 IN IP4 127.0.0.1 // s=- // t=0 0 // a=group:BUNDLE 0 1 // m=audio 9 UDP/TLS/RTP/SAVPF 111 …
ICE — Interactive Connectivity Establishment
ICE finds the best network path. It gathers candidates (host addresses, server-reflexive via STUN, relayed via TURN) and tries them in priority order.
DTLS + SRTP
All media is encrypted with SRTP keyed via DTLS handshake — mandatory in WebRTC. You cannot disable encryption.
Browser Support
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
RTCPeerConnection | 23+ | 22+ | 11+ | 79+ |
getUserMedia | 53+ | 36+ | 11+ | 79+ |
getDisplayMedia | 72+ | 66+ | 13+ | 79+ |
RTCDataChannel | 31+ | 22+ | 11+ | 79+ |
| Unified Plan SDP | 72+ | 63+ | 12.1+ | 79+ |
Safari requires
playsInlineon<video>and a user gesture before audio plays. Always test Safari separately.
Minimal End-to-End Skeleton
// ---- CALLER ---- const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }); // Add local tracks first, then create offer const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); stream.getTracks().forEach(t => pc.addTrack(t, stream)); pc.onicecandidate = ({ candidate }) => { if (candidate) signaling.send({ type: 'ice', candidate }); }; const offer = await pc.createOffer(); await pc.setLocalDescription(offer); signaling.send({ type: 'offer', sdp: pc.localDescription }); // ---- CALLEE ---- const pc2 = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }); pc2.ontrack = ({ streams }) => { document.getElementById('remoteVideo').srcObject = streams[0]; }; signaling.on('offer', async ({ sdp }) => { await pc2.setRemoteDescription(sdp); const answer = await pc2.createAnswer(); await pc2.setLocalDescription(answer); signaling.send({ type: 'answer', sdp: pc2.localDescription }); }); signaling.on('answer', async ({ sdp }) => { await pc.setRemoteDescription(sdp); }); signaling.on('ice', async ({ candidate }) => { await pc.addIceCandidate(candidate); });
Key Gotchas
- Add tracks before creating an offer — tracks added after require renegotiation via
onnegotiationneeded. - Never set remote description before local — always
setLocalDescriptionfirst on the side that created the SDP. - ICE candidates can arrive before
setRemoteDescription— buffer them and add after remote description is set. RTCSessionDescriptionis now optional — pass plain{ type, sdp }objects directly tosetLocalDescription/setRemoteDescription.- Trickle ICE is the default; wait for
icegatheringstate === 'complete'only if your signaling can't handle incremental candidates. - HTTPS required —
getUserMediaand WebRTC in general are restricted to secure contexts (https://orlocalhost).
RTCPeerConnection Constructor
const pc = new RTCPeerConnection(configuration);
configuration property | Type | Default | Description |
|---|---|---|---|
iceServers | RTCIceServer[] | [] | STUN/TURN servers |
iceTransportPolicy | "all" | "relay" | "all" | "relay" forces TURN |
bundlePolicy | "balanced" | "max-compat" | "max-bundle" | "balanced" | How to bundle media |
rtcpMuxPolicy | "require" | "require" | Must mux RTCP |
certificates | RTCCertificate[] | auto-generated | Pre-generated DTLS certs |
iceCandidatePoolSize | number | 0 | Pre-gather N candidates |
Useful Utilities
// Check if WebRTC is available const supported = typeof RTCPeerConnection !== 'undefined'; // Get browser capabilities const caps = RTCRtpReceiver.getCapabilities('video'); console.log(caps.codecs); // [{mimeType:'video/VP8', …}, …] // Generate a certificate upfront (avoids DTLS delay) const cert = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256', }); const pc = new RTCPeerConnection({ certificates: [cert] });