Skip to content

Screen Capture API (getDisplayMedia)

Published Updated

The Screen Capture API extends Media Capture and Streams with navigator.mediaDevices.getDisplayMedia(), which prompts the user to pick a screen, window, or tab and returns a MediaStream of that display surface for recording or sending over the network.

Per MDN’s browser-compat-data, getDisplayMedia() is supported on desktop Chrome (since version 72), Edge (79), Firefox (66), and Safari (13). Chrome for Android (72–88) and Firefox for Android (66–79) previously exposed the method but calls always failed with NotAllowedError; current browser-compat-data records both platforms as unsupported, and Safari on iOS does not support it either. Per MDN, the feature has “Limited availability” and is not part of the Baseline widely-available set, so treat it as unavailable until you confirm support on your target browser rather than assuming it works everywhere MediaDevices does.

async function startCapture() {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: { displaySurface: 'browser' },
audio: false,
});
return stream;
} catch (err) {
console.error(`getDisplayMedia failed: ${err.name}`);
return null;
}
}

Per MDN, getDisplayMedia() requires transient user activation (it must be called from a user gesture such as a click handler) and prompts the user every time — the choice of source cannot be persisted or made automatically. The video option defaults to true, so a video track is always requested unless you explicitly pass video: false — which MDN says rejects with a TypeError, since capturing audio alone is not supported.

Feature-detect getDisplayMedia before calling it, and fall back to a UI that explains screen sharing isn’t available when it’s missing or the call fails:

async function captureScreenOrFallback() {
if (!navigator.mediaDevices?.getDisplayMedia) {
// Not supported in this browser — show a message instead of a blank screen.
return null;
}
try {
return await navigator.mediaDevices.getDisplayMedia({ video: true });
} catch {
// User declined the prompt, or no capture source was available.
return null;
}
}
  • Per MDN, getDisplayMedia() is only available in secure contexts (HTTPS) and requires the display-capture Permissions Policy, which defaults to self (same-origin) — a cross-origin embedding iframe needs an explicit allow="display-capture" to use it.
  • Per the MDN guide, capture sources cannot be enumerated with enumerateDevices() and never fire devicechange events, so build your own UI around the picker the browser shows rather than listing sources yourself.
  • Per the MDN guide, constraints you pass do not filter what the user is offered — they are applied to the stream only after the user has already chosen a source, so a constraint you need cannot be used to narrow the picker.
  • Per the MDN guide, an audio track is optional and browser-dependent: even when you request audio: true, the returned stream may carry video only.
  • Per browser-compat-data, Chrome for Android 72–88 and Firefox for Android 66–79 exposed getDisplayMedia but calls always failed with NotAllowedError; current entries mark both platforms unsupported, so feature-detecting the method’s presence alone is not a reliable signal of support on older releases.