Skip to content

WebRTC: peer-to-peer audio, video, and data in the browser

In one line: WebRTC, together with the Media Capture and Streams API, gives the web audio and video conferencing, file exchange, and screen sharing — connections between peers can be made without special drivers or plug-ins, and often without any intermediary server once the connection is set up.

  • RTCPeerConnection represents a WebRTC connection between the local computer and a remote peer; once established and opened, media streams and/or data channels can be added to it.
  • MediaStreamTrack represents a single track of media data within a stream — audio, video, or text.
  • RTCDataChannel, added to an open RTCPeerConnection, carries arbitrary application data directly between peers alongside (or instead of) media.

MediaDevices.getUserMedia() requests access to the user’s camera and microphone, resolving with a MediaStream:

const constraints = { audio: true, video: { width: 1280, height: 720 } };
const stream = await navigator.mediaDevices.getUserMedia(constraints);
videoElement.srcObject = stream;

navigator.mediaDevices.enumerateDevices() lists available input devices. Passing a device’s deviceId as a bare constraint value is only a preference the browser may override; to mandate that specific device, pass it as { exact: deviceId } instead.

WebRTC cannot create a connection without first exchanging session information — offers, answers, and network candidates — between the two peers, and MDN is explicit that this exchange needs “some sort of server in the middle”: WebRTC does not define this signal channel itself, so it can be carried over any transport the app already has (WebSocket, an existing API, etc.). A typical flow:

const pc = new RTCPeerConnection();
pc.addTrack(stream.getTracks()[0], stream);
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// Send `offer` to the remote peer over your own signaling channel.

The receiving peer calls setRemoteDescription() with that offer, creates its own answer, and sends it back over the same signaling channel — after which the two RTCPeerConnection instances negotiate media/data flow between them, often (but not always) without any server relaying the media itself.

Per MDN’s compatibility data, the RTCPeerConnection() constructor has Baseline “Widely available” status: the feature has worked across major browsers since September 2017.

Browser / PlatformSupportSinceConfidenceSourceNotes
Chrome (Desktop)✅ yes56highrefPrefixed `webkitRTCPeerConnection` supported since Chrome 23.
Edge (Desktop)✅ yes15highref
Firefox (Desktop)✅ yes44highrefPrefixed `mozRTCPeerConnection` supported since Firefox 22.
Firefox (Android)✅ yes44highrefPrefixed `mozRTCPeerConnection` supported since Firefox for Android 24.
Safari (macOS)✅ yes11highref

Source: spec · MDN · Last verified 2026-07-20 · Confidence: high

async function startCall(constraints) {
if (!('RTCPeerConnection' in window) || !navigator.mediaDevices?.getUserMedia) {
// WebRTC isn't available — fall back to a non-realtime path
// (e.g. an upload form) instead of attempting a call.
return null;
}
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const pc = new RTCPeerConnection();
stream.getTracks().forEach((track) => pc.addTrack(track, stream));
return pc;
}
  • Feature-detect both RTCPeerConnection and navigator.mediaDevices.getUserMedia before starting a call, and provide a fallback path when either is missing.
  • Call getUserMedia() only in response to a context the user understands — it triggers a permission prompt for camera/microphone access, unless the browser already remembers a prior grant for your origin.
  • Build your own signaling channel; WebRTC does not provide one, only the connection once offer/answer/candidates have been exchanged.
  • Add tracks to RTCPeerConnection before creating the offer so they’re included in the negotiated session.
  • Use enumerateDevices() plus a deviceId: { exact: deviceId } constraint when you need to mandate a specific camera or microphone rather than the default device.