keyboard_backspace wifi_off

Capture handle

Screen capturing is not (yet) supported on your device

Capture Handle is not (yet) supported on your device

Capture Handle enables screen capturing web apps to reliably identify the captured web app if it has opted-in, enabling better collaboration like remote control for example. A great use-case for this is a screen capture web app that can remotely control a presentation inside the web app that is captured.

The user of the capturing web app then doesn't need to switch between the capturing and captured app anymore to control that presentation.

The captured app can opt-in through a call to navigator.mediaDevices.setCaptureHandleConfig(config). The config parameter has a handle property containing a string that uniquely identifies the captured app.

The capturing app retrieves the handle by calling getCaptureHandle on the VideoTrack of the screen capturing MediaStream. It then uses that handle in messages it sends to the captured app through BroadcastChannel. These messages instruct the captured app to go to the previous or next image in the gallery.

Demo

Click the button "Open page" below to open a page containing an image gallery. Then capture the screen of that page by clicking the button "Share screen". After that, you can go back and forth between the images in the gallery from this page by clicking the "Previous" and "Next" buttons. No need to switch between this app and the captured app anymore!

// capturing side let controller; // CaptureController keeps the focus on the capturing web app if ('CaptureController' in window && 'setFocusBehavior' in CaptureController.prototype) { controller = new CaptureController(); controller.setFocusBehavior('no-focus-change'); } const stream = await navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: 'browser', }, audio: true, surfaceSwitching: 'exclude', selfBrowserSurface: 'exclude', preferCurrentTab: false, systemAudio: 'include', monitorTypeSurfaces: "exclude", ...(controller && {controller}) }); const [videoTrack] = stream.getVideoTracks(); let captureHandle = videoTrack.getCaptureHandle(); if (captureHandle) { previousButton.disabled = false; nextButton.disabled = false; } videoTrack.addEventListener('capturehandlechange', (e) => { captureHandle = e.target.getCaptureHandle(); }); const broadcastChannel = new BroadcastChannel("capture-handle"); previousButton.addEventListener('click', () => { broadcastChannel.postMessage({ handle: captureHandle.handle, command: 'previous', }); }); nextButton.addEventListener('click', () => { broadcastChannel.postMessage({ handle: captureHandle.handle, command: 'next', }); }); // captured side const config = { handle: crypto.randomUUID(), exposeOrigin: true, permittedOrigins: ['*'], }; navigator.mediaDevices.setCaptureHandleConfig(config); const gallery = document.querySelector('image-gallery'); const broadcastChannel = new BroadcastChannel("capture-handle"); broadcastChannel.addEventListener('message', ({data}) => { const {handle, command} = data; // only accept commands if the handle matches if(handle === config.handle) { switch(command) { case 'previous': gallery.previous(); break; case 'next': gallery.next(); break; } } });

Documentation

Capture handle on Chrome Developers.

Browser support

Capture Handle is supported in Chrome and Edge 102+.

What PWA Can Do Today A showcase of what is possible with Progressive Web Apps today