offscreen Permission

8 min read

offscreen Permission

The offscreen permission enables the Chrome chrome.offscreen API, which allows extensions to create offscreen documents for performing operations that require DOM access from the extension’s service worker context. This is a Manifest V3-only feature that replaces the background page DOM access available in Manifest V2.

Overview

Property Value
Permission string "offscreen"
API chrome.offscreen
Minimum Chrome version 94+
Manifest requirement Must be declared in permissions array

The offscreen document is a hidden HTML document that runs in the context of your extension but has no visible UI. It provides a way to perform DOM-related operations from the service worker, which otherwise has no access to the DOM.

API Methods

createDocument

Creates an offscreen document with the specified parameters:

chrome.offscreen.createDocument({
  url: 'offscreen.html',
  reasons: [chrome.offscreen.Reason.DOM_SCRAPING],
  justification: 'Need to parse HTML content for data extraction'
});

Parameters:

closeDocument

Closes the currently open offscreen document:

await chrome.offscreen.closeDocument();

hasDocument

Checks whether an offscreen document currently exists (Chrome 116+):

const exists = await chrome.offscreen.hasDocument();

Reason Enum Values

The chrome.offscreen.Reason enum provides various reasons for creating an offscreen document. Chrome supports the following reasons:

Reason Description
TESTING Used for automated testing scenarios
AUDIO_PLAYBACK Audio playback from background context
IFRAME_SCRIPTING Scripting iframes from background
DOM_SCRAPING Parsing and extracting data from HTML
BLOBS Working with Blob objects
DOM_PARSER HTML/XML parsing operations
USER_MEDIA Capturing user media (webcam/microphone)
DISPLAY_MEDIA Capturing display media
WEB_RTC WebRTC operations
CLIPBOARD Clipboard read/write operations
LOCAL_STORAGE Local storage operations
WORKERS Web Worker management
BATTERY_STATUS Battery API access
MATCH_MEDIA Media query matching
GEOLOCATION Geolocation API access

Constraints

One Document Limit

Only one offscreen document can exist at a time per extension. Attempting to create a new one while one already exists will result in an error. Always check with hasDocument() before creating:

async function createOffscreenIfNeeded() {
  if (await chrome.offscreen.hasDocument()) {
    return;
  }
  
  await chrome.offscreen.createDocument({
    url: 'offscreen.html',
    reasons: [chrome.offscreen.Reason.DOM_SCRAPING],
    justification: 'Need to parse HTML for data extraction'
  });
}

Reason Requirement

At least one reason must be specified when creating the document. Providing an empty array will cause an error.

No UI Visibility

The offscreen document has no visible UI to the user. It exists purely in memory and is not rendered in any window.

Communication via Messaging

Since the offscreen document runs in isolation, communication with your service worker or content scripts must use chrome.runtime messaging:

// In service worker
chrome.runtime.sendMessage({ action: 'doWork', data: '...' });

// In offscreen document
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  // Handle message and respond
  sendResponse({ result: '...' });
});

Manifest Declaration

To use the offscreen API, declare the permission in your manifest.json:

{
  "name": "My Extension",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "offscreen"
  ],
  "background": {
    "service_worker": "background.js"
  }
}

Note: The offscreen permission is only available in Manifest V3. It is not available in Manifest V2.

Use Cases

DOM Parsing

Parse HTML content that cannot be handled directly in the service worker:

// In service worker
async function parseHTML(html) {
  await chrome.offscreen.createDocument({
    url: 'offscreen.html',
    reasons: [chrome.offscreen.Reason.DOM_PARSER],
    justification: 'Parsing HTML content for extraction'
  });
  
  // Send HTML to offscreen document for parsing
  chrome.runtime.sendMessage({
    type: 'PARSE_HTML',
    html: html
  });
  
  // Wait for response (implementation details vary)
  await chrome.offscreen.closeDocument();
}

Audio Playback

Play audio from the background service worker context:

async function playAudio(audioUrl) {
  await chrome.offscreen.createDocument({
    url: 'audio-player.html',
    reasons: [chrome.offscreen.Reason.AUDIO_PLAYBACK],
    justification: 'Playing audio notifications from background'
  });
  
  chrome.runtime.sendMessage({
    type: 'PLAY_AUDIO',
    url: audioUrl
  });
}

Clipboard Operations

Perform advanced clipboard operations:

async function readClipboard() {
  if (await chrome.offscreen.hasDocument()) {
    await chrome.offscreen.closeDocument();
  }
  
  await chrome.offscreen.createDocument({
    url: 'clipboard.html',
    reasons: [chrome.offscreen.Reason.CLIPBOARD],
    justification: 'Reading clipboard content'
  });
  
  return new Promise((resolve) => {
    chrome.runtime.onMessage.addListener(function onMessage(message) {
      if (message.type === 'CLIPBOARD_CONTENT') {
        chrome.runtime.onMessage.removeListener(onMessage);
        resolve(message.content);
      }
    });
  });
}

Geolocation

Access geolocation from the background context:

async function getLocation() {
  await chrome.offscreen.createDocument({
    url: 'geolocation.html',
    reasons: [chrome.offscreen.Reason.GEOLOCATION],
    justification: 'Tracking user location for notifications'
  });
  
  return new Promise((resolve) => {
    chrome.runtime.onMessage.addListener(function onMessage(message) {
      if (message.type === 'LOCATION') {
        chrome.runtime.onMessage.removeListener(onMessage);
        resolve(message.coords);
      }
    });
  });
}

Code Examples

Guard Pattern

Always check if an offscreen document exists before creating:

async function ensureOffscreen(reason) {
  if (await chrome.offscreen.hasDocument()) {
    return;
  }
  
  await chrome.offscreen.createDocument({
    url: 'offscreen.html',
    reasons: [reason],
    justification: 'Required for extension functionality'
  });
}

Complete Workflow

A complete example of creating, communicating, and closing:

async function scrapePageData(url) {
  // Create offscreen document
  await chrome.offscreen.createDocument({
    url: 'offscreen.html',
    reasons: [chrome.offscreen.Reason.DOM_SCRAPING],
    justification: 'Scraping page content for data extraction'
  });
  
  // Send message to offscreen document
  const response = await chrome.runtime.sendMessage({
    type: 'SCRAPE_URL',
    url: url
  });
  
  // Close the document when done
  await chrome.offscreen.closeDocument();
  
  return response.data;
}

Cross-references

See Also

Frequently Asked Questions

What are offscreen documents in Manifest V3?

Offscreen documents are hidden pages that extension can create to perform tasks that require a DOM, like playing audio or using certain APIs.

How do I create an offscreen document?

Use chrome.offscreen.createDocument() with a specified reason and the HTML file to load. Only one offscreen document can exist per extension at a time. —

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.

No previous article
No next article