Work with documentId
A documentId is a UUID string that identifies a unique document loaded in a tab or frame. This guide explains what documentId is, why it is useful, and how to use it in the WebExtension APIs.
Tabs, frames, and documents
A browser tab, identified by a tabId, is the top-level container for web content. Within a tab, content can be structured into multiple frames: the main (outermost) frame, which has a frameId of 0, and any nested <iframe> elements, each with a frameId. As the top frameId is 0, frameId cannot be used to uniquely identify all frames across all tabs.
Each frame holds a document, the HTML page loaded at a URL. The relationship between these three concepts is:
- A tab contains one or more frames.
- A frame contains a document.
- Navigating a frame to a new URL replaces its document but keeps the same frame and, therefore, the same
frameId.
This means that the combination of tabId and frameId identifies a frame (a stable browsing context), but not the document loaded in that frame.
Documents and frames are also present in non-tab contexts, including but not limited to:
Operations using tab and frame IDs
Many WebExtension APIs use tabId and frameId to identify where to perform an operation:
- Script and CSS injection:
scripting.executeScript(),scripting.insertCSS(), andscripting.removeCSS()accept atabIdand optionalframeIdsin theirscripting.InjectionTargetto specify where to inject into. - User script injection:
userScripts.execute()takestabIdandframeIdsin itstarget. - Messaging:
tabs.sendMessage()andtabs.connect()accept atabIdand optionalframeIdto direct a message to its recipient. - Frame information:
webNavigation.getFrame()andwebNavigation.getAllFrames()usetabIdandframeIdto look up or enumerate frame details. - Events: Navigation events (
webNavigation.onCommitted,webNavigation.onCompleted, and others), request events (webRequest.onBeforeRequestand others), andproxy.onRequestall includetabIdandframeIdto identify where an event occurred.
Because frameId identifies the frame rather than its content, there is a potential race condition. After your extension has obtained the tabId and frameId, the loaded document may change, so the extension's subsequent operation no longer targets the intended document. documentId was introduced to address this problem.
What is a documentId?
A documentId is assigned to each document when it loads and remains constant throughout the document's lifetime. When a frame navigates to a new URL, it retains its frameId but receives a new documentId. This distinguishes documentId from frameId: a frameId identifies the browsing context (the frame element itself), whereas a documentId identifies the document loaded within it.
The documentId also correctly handles edge cases that frameId cannot distinguish:
- Navigations: Each new document load, including cross-origin navigations, receives a new
documentIdeven though theframeIdis unchanged. - Reloads: A page reload creates a new
documentId, indicating a fresh document. history.pushState()and fragment updates: These don't create a new document, so thedocumentIdis unchanged.
As it changes with each document load, the ID your extension obtained for a document remains valid only for that document. If the frame has navigated away, the documentId no longer matches. So, if your extension injects a script or sends a message using the documented ID after the navigation, the operation fails rather than silently targeting the wrong document.
When a document is restored from the back/forward cache (bfcache), its original documentId is also restored.
Get a documentId
There are several ways to obtain a documentId:
- Call
runtime.getDocumentId()with awindowor frame element from within a content script. - Read the
documentIdorparentDocumentIdproperty in the results ofwebNavigation.getFrame()orwebNavigation.getAllFrames(). - Read the
documentIdorparentDocumentIdfrom event details inwebNavigationevents (for events where the document of the navigation target is known when the event fires). - Read the
documentIdfromwebRequestevent details. - Read the
documentIdfromruntime.MessageSenderwhen receiving messages usingruntime.onMessage,runtime.onConnect, and related listeners. - Read the
documentIdfrom the results ofruntime.getContexts().
Using documentId to target documents
When you have a documentId, you can use it to target that document:
- Script and CSS injection: Use
documentIdsinscripting.InjectionTargetwithscripting.executeScript(),scripting.insertCSS(), andscripting.removeCSS()to inject into specific documents. - User script injection: Set
documentIdsin thetargetparameter ofuserScripts.execute(). - Messaging: Pass
documentIdin theoptionsparameter oftabs.connect()ortabs.sendMessage()to send to a document in a tab. - Frame lookup: Pass
documentIdtowebNavigation.getFrame()as an alternative totabIdandframeId. If you also providetabIdandframeId, the frame is only returned when all three match.
APIs supporting documentId
These APIs include documentId support.
Obtain a documentId
runtime.getDocumentId()returns the document UUID of a target window or frame element.
documentId in return values and event details
runtime.getContexts()returns adocumentIdfor each extension context and supports adocumentIdsfilter property.runtime.MessageSenderincludesdocumentId, available inruntime.onConnect,runtime.onMessage,runtime.onMessageExternal,runtime.onConnectExternal,runtime.onUserScriptMessage, andruntime.onUserScriptConnectlisteners.scripting.executeScript()returnsdocumentIdin eachInjectionResult.userScripts.execute()results includedocumentId.webNavigation.getAllFrames()returnsdocumentIdandparentDocumentIdfor each frame.webNavigation.getFrame()returnsdocumentIdandparentDocumentId.webNavigation.onCommitted,webNavigation.onDOMContentLoaded,webNavigation.onCompleted,webNavigation.onErrorOccurred,webNavigation.onReferenceFragmentUpdated, andwebNavigation.onHistoryStateUpdatedincludedocumentIdandparentDocumentIdin event details.webNavigation.onBeforeNavigatemay have aparentDocumentIdwhen a frame navigates, but doesn't havedocumentIdbecause the event fires before a document is loaded.- All
webRequestevents —webRequest.onBeforeRequest,webRequest.onBeforeSendHeaders,webRequest.onSendHeaders,webRequest.onHeadersReceived,webRequest.onAuthRequired,webRequest.onBeforeRedirect,webRequest.onResponseStarted,webRequest.onCompleted, andwebRequest.onErrorOccurred— includedocumentIdandparentDocumentIdwhen applicable. proxy.RequestDetailsincludesdocumentIdandparentDocumentIdwhen applicable.declarativeNetRequest.onRuleMatchedDebugincludesdocumentIdwhen applicable.
documentId for targeting
scripting.InjectionTargetsupportsdocumentIdsto target specific documents inscripting.executeScript(),scripting.insertCSS(), andscripting.removeCSS().userScripts.execute()targetsupportsdocumentIds.tabs.connect()optionssupportsdocumentIdto target a specific document.tabs.sendMessage()optionssupportsdocumentIdto target a specific document.webNavigation.getFrame()acceptsdocumentIdas an alternative totabIdandframeId.
Future developments
The WebExtensions Community Group (WECG) is discussing relaxing the requirement to provide tabId alongside documentId when targeting documents. See WECG issue #91 for the discussion.