This guide explains different approaches for recording audio and video from a tab, window, or
screen using APIs such as [`browser.tabCapture`](https://developer.chrome.com/docs/extensions/reference/api/tabCapture) or
[`getDisplayMedia()`](https://developer.mozilla.org/docs/Web/API/MediaDevices/getDisplayMedia).

## Screen recording

For screen recording, call [`getDisplayMedia()`](https://developer.mozilla.org/docs/Web/API/MediaDevices/getDisplayMedia), which triggers the dialog box
shown below. This provides the user with the ability to select which tab, window or screen they wish
to share and provides a clear indication that recording is taking place.
![Screen share dialog for example.com](https://developer.chrome.com/static/docs/extensions/how-to/web-platform/screen-capture/image/screen-share-dialog-exam-659e9c8ddbf89.png) Screen share dialog for example.com.

The following example requests access to record both audio and video.

    const stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: true });

If called within a content script, recording will automatically end when the user navigates to a new
page. To record in the background and across navigations, use an
[offscreen document](https://developer.chrome.com/blog/Offscreen-Documents-in-Manifest-v3) with the `DISPLAY_MEDIA` reason.

## Tab capture based on user gesture

Calling [`getDisplayMedia()`](https://developer.mozilla.org/docs/Web/API/MediaDevices/getDisplayMedia) results in the browser showing a dialog which asks
the user what they would like to share. However, in some cases the user has just clicked on the
[action button](https://developer.chrome.com/docs/extensions/develop/ui#actions) to invoke your extension for a specific tab, and you would like to
immediately start capturing the tab without this prompt.

### Record audio and video in the background

Starting in Chrome 116, you can call the [`browser.tabCapture`](https://developer.chrome.com/docs/extensions/reference/api/tabCapture) API in a service worker
to obtain a stream ID following user gesture. This can then be passed to an offscreen document to
start recording.

In your service worker:

    browser.action.onClicked.addListener(async (tab) => {
      const existingContexts = await browser.runtime.getContexts({});

      const offscreenDocument = existingContexts.find(
        (c) => c.contextType === 'OFFSCREEN_DOCUMENT'
      );

      // If an offscreen document is not already open, create one.
      if (!offscreenDocument) {
        // Create an offscreen document.
        await browser.offscreen.createDocument({
          url: 'offscreen.html',
          reasons: ['USER_MEDIA'],
          justification: 'Recording from browser.tabCapture API',
        });
      }

      // Get a MediaStream for the active tab.
      const streamId = await browser.tabCapture.getMediaStreamId({
        targetTabId: tab.id
      });

      // Send the stream ID to the offscreen document to start recording.
      browser.runtime.sendMessage({
        type: 'start-recording',
        target: 'offscreen',
        data: streamId
      });
    });

Then, in your offscreen document:

    browser.runtime.onMessage.addListener(async (message) => {
      if (message.target !== 'offscreen') return;
      
      if (message.type === 'start-recording') {
        const media = await navigator.mediaDevices.getUserMedia({
          audio: {
            mandatory: {
              chromeMediaSource: "tab",
              chromeMediaSourceId: message.data,
            },
          },
          video: {
            mandatory: {
              chromeMediaSource: "tab",
              chromeMediaSourceId: message.data,
            },
          },
        });

        // Continue to play the captured audio to the user.
        const output = new AudioContext();
        const source = output.createMediaStreamSource(media);
        source.connect(output.destination);

        // TODO: Do something to record the MediaStream.
      }
    });

For a full example, see the [Tab Capture - Recorder](https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/sample.tabcapture-recorder) sample.

### Record audio and video in a new tab

Prior to Chrome 116, it was not possible to use the [`browser.tabCapture`](https://developer.chrome.com/docs/extensions/reference/api/tabCapture) API in a
service worker or to consume a stream ID created by that API in an offscreen document. Both of these
are requirements for the approach above.

Instead, you can open an extension page in a new tab or window, and directly obtain a stream. Set
the `targetTabId` property to capture the correct tab.

Start by opening an extension page (perhaps in your popup or service worker):

    browser.windows.create({ url: browser.runtime.getURL("recorder.html") });

Then, in your extension page:

    browser.tabCapture.getMediaStreamId({ targetTabId: tabId }, async (id) => {
      const media = await navigator.mediaDevices.getUserMedia({
        audio: {
          mandatory: {
            chromeMediaSource: "tab",
            chromeMediaSourceId: id,
          },
        },
        video: {
          mandatory: {
            chromeMediaSource: "tab",
            chromeMediaSourceId: id,
          },
        },
      });

      // Continue to play the captured audio to the user.
      const output = new AudioContext();
      const source = output.createMediaStreamSource(media);
      source.connect(output.destination);
    });

Alternatively, consider using the [screen recording](https://developer.chrome.com/docs/extensions/how-to/web-platform/screen-capture#screen-recording) approach which allows you to
record in the background using an offscreen document, but shows the user a dialog to select a tab,
window or screen to record from.

### Record audio in a popup

> [!CAUTION]
> **Caution:** This approach only works for audio, as attempting to capture video from the popup causes focus to move and the popup to close.

If you only need to record audio, you can directly obtain a stream in the extension popup using
[browser.tabCapture.capture](https://developer.chrome.com/docs/extensions/reference/api/tabCapture#method-capture). When the popup closes, recording will be stopped.

    browser.tabCapture.capture({ audio: true }, (stream) => {
      // Continue to play the captured audio to the user.
      const output = new AudioContext();
      const source = output.createMediaStreamSource(stream);
      source.connect(output.destination);

      // TODO: Do something with the stream (e.g record it)
    });

If you need the recording to persist across navigations, consider using the approach described
in the [previous section](https://developer.chrome.com/docs/extensions/how-to/web-platform/screen-capture#audio-and-video-offscreen-doc).

## Other considerations

For more information on how to record a stream, see the [MediaRecorder](https://developer.mozilla.org/docs/Web/API/MediaRecorder) API.