Skip to main content
Record the screen from an extension page with getDisplayMedia, encode it with MediaRecorder, and save the result with the downloads API.

Choose a capture API

getDisplayMedia needs no manifest permission. The browser shows a source picker, and that prompt is the consent. tabCapture skips the picker but requires the tabCapture permission and a prior user gesture on the extension, such as an action click.

Manifest

Add offscreen to the permissions only when you record from an offscreen document.
manifest.json

Open a recorder page

A popup closes when it loses focus, which kills its recording. Host the recorder on a dedicated page instead. Put recorder.html and recorder.js in the pages/ special folder, and Extension.js compiles them as entrypoints.
background.js

Record with getDisplayMedia

getDisplayMedia requires a user gesture, so call it from a click handler, never on page load.
pages/recorder.js
The blob URL works here because the recorder is a document, not a service worker.

Capture the active tab instead

With tabCapture, the background hands a stream id to your page, and the page turns it into a stream. No picker appears.
pages/recorder.js
Feed the resulting stream into the same MediaRecorder flow as above.

Record in the background

To keep recording without any visible extension page, Chrome offers offscreen documents. Create one with chrome.offscreen.createDocument and the USER_MEDIA reason, then run the capture code there. This needs the offscreen permission and stays Chromium-only.

Run it

Click the action icon to open the recorder page. Start a capture, stop it, and the WebM file lands in your downloads.

Firefox notes

  • getDisplayMedia and MediaRecorder work in Firefox extension pages, so the main recipe is portable.
  • Firefox does not support tabCapture or offscreen documents.
  • Use browser-specific manifest fields to keep the tabCapture permission out of the Firefox build.

Start from a template

The special-folders-pages template shows the pages/ layout that hosts the recorder page.
Repository: extension-js/examples/special-folders-pages

Best practices

  • Stop every track when recording ends, so the browser removes the sharing indicator.
  • Choose the capture API per browser: getDisplayMedia everywhere, tabCapture for Chromium tab-only flows.
  • Keep saveAs: true, so users choose where recordings go.
  • Chunk long recordings with recorder.start(timeslice) to bound memory use.

Next steps