WebRTC enables real-time communication directly in the browser — video calls, audio, data channels, and peer-to-peer file transfer. Firefox has strong WebRTC support. Here's the practical guide.
What WebRTC Can Do
- Video/audio calls: getUserMedia captures camera/mic, RTCPeerConnection handles the connection
- Screen sharing: getDisplayMedia captures screen/window/tab
- P2P data: RTCDataChannel for low-latency peer-to-peer data transfer
- File transfer: Binary data over data channels (no server needed for transfer)
WebRTC in Firefox: Permissions
Camera/Microphone: Firefox prompts for permission on first use. Permission is per-origin.
Check permissions: Click lock icon → Connection → More Information → Permissions → Access your Camera.
Screen sharing (getDisplayMedia): Always prompts with a picker — can't be pre-authorized.
Privacy tip: After calls, revoke permissions from the address bar. Or in Settings → Privacy → Permissions → Camera/Microphone → Settings.
Basic getUserMedia
// Request camera + microphone
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { max: 30 }
},
audio: {
echoCancellation: true,
noiseSuppression: true
}
});
// Attach to video element
const video = document.querySelector('video');
video.srcObject = stream;
video.play();
// Stop all tracks when done (release camera)
stream.getTracks().forEach(track => track.stop());
Enumerating Devices
// List available cameras and microphones
const devices = await navigator.mediaDevices.enumerateDevices();
devices.filter(d => d.kind === 'videoinput').forEach(d => {
console.log('Camera:', d.label, d.deviceId);
});
devices.filter(d => d.kind === 'audioinput').forEach(d => {
console.log('Microphone:', d.label, d.deviceId);
});
// Use a specific device
const stream = await navigator.mediaDevices.getUserMedia({
video: { deviceId: { exact: specificDeviceId } }
});
Firefox behavior: Device labels are only shown after permission is granted. Before permission: deviceId is visible but label is empty (for privacy).
Screen Sharing
// Request screen/window/tab capture
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: {
cursor: 'always', // Show cursor in recording
displaySurface: 'window' // 'monitor', 'window', 'browser'
},
audio: false // Screen audio (supported in Chrome but limited in Firefox)
});
const video = document.querySelector('video');
video.srcObject = screenStream;
Firefox vs Chrome screen audio: Chrome supports capturing system audio with screen sharing. Firefox does not capture system audio with getDisplayMedia. This is a known limitation.
Firefox allows sharing specific tab: In Firefox's screen picker, you can select a specific browser tab to share, same as Chrome.
RTCPeerConnection (Video Calls)
A minimal video call setup:
// Signaling server (WebSocket) handles exchanging SDP and ICE candidates
// This example uses a hypothetical signaling channel
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
// Add local stream
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// Handle incoming stream
pc.ontrack = (event) => {
remoteVideo.srcObject = event.streams[0];
};
// Exchange ICE candidates via signaling
pc.onicecandidate = (event) => {
if (event.candidate) {
signalingChannel.send({ candidate: event.candidate });
}
};
// Caller creates offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
signalingChannel.send({ sdp: offer });
// Callee receives offer, creates answer
pc.setRemoteDescription(remoteOffer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
signalingChannel.send({ sdp: answer });
// Both sides add received ICE candidates
pc.addIceCandidate(receivedCandidate);
Data Channels
P2P data transfer without a media stream:
const pc = new RTCPeerConnection({ iceServers: [...] });
// Create data channel on the caller side
const dataChannel = pc.createDataChannel('my-channel', {
ordered: true, // Guaranteed delivery (TCP-like)
maxRetransmits: 0 // 0 = unreliable (UDP-like, use for gaming)
});
dataChannel.onopen = () => console.log('Channel open');
dataChannel.onmessage = (e) => console.log('Received:', e.data);
// Send data
dataChannel.send('Hello!');
dataChannel.send(JSON.stringify({ type: 'ping' }));
// Binary data (file transfer)
const buffer = await file.arrayBuffer();
dataChannel.send(buffer);
// On the receiving side
pc.ondatachannel = (event) => {
const channel = event.channel;
channel.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) {
// Handle file chunk
}
};
};
WebRTC and Privacy: IP Leaks
The IP leak problem: WebRTC can reveal your local network IP (192.168.x.x) and your real public IP even when using a VPN.
Why: WebRTC ICE (Interactive Connectivity Establishment) gathers all network interface addresses to find the best connection path. This includes addresses that bypass the VPN tunnel.
Firefox mitigation:
In about:config:
media.peerconnection.ice.default_address_only = true
media.peerconnection.ice.no_host = true
default_address_only = true: Only use the default network interface (not all interfaces), reducing leak surface.
ice.no_host = true: Don't include local/host addresses at all.
Test for leaks: Use a WebRTC IP leak test site. With these settings, your real IP should not appear when behind a VPN.
Full disable (breaks WebRTC):
media.peerconnection.enabled = false
Debugging WebRTC in Firefox
about:webrtc: Firefox's built-in WebRTC diagnostics page. Shows:
- Active ICE connections
- ICE candidates gathered
- Statistics per peer connection (packet loss, jitter, bandwidth)
- Session logging
To use:
- Open a WebRTC-based app (video call, etc.)
- In another tab: about:webrtc
- See all active connections with their statistics
This is useful for:
- Diagnosing video call quality issues
- Checking which ICE candidates were used
- Verifying TURN/STUN server selection
TURN Servers for Firewalls
ICE can fail when both peers are behind strict firewalls/NAT. TURN servers relay the traffic:
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.example.com:3478' },
{
urls: 'turn:turn.example.com:3478',
username: 'user',
credential: 'password'
}
]
});
Free TURN servers: None reliable for production. For production apps, use Twilio, Xirsys, or self-host coturn.
In development: localhost connections usually work without TURN (same machine or local network).
Firefox WebRTC vs Chrome
Codec support:
- Both support VP8, VP9, H.264
- Firefox supports AV1 video codec
- Firefox supports Opus (audio), G.711
Simulcast: Firefox supports simulcast (sending multiple quality streams simultaneously). Important for video conferences with many participants.
Screen audio: Chrome can capture system audio with getDisplayMedia. Firefox cannot (platform limitation).
WebRTC Stats API: Both support RTCPeerConnection.getStats(). Firefox and Chrome return slightly different stat names — check for both names in cross-browser code.
Top comments (0)