activeTab permission
The activeTab permission gives an extension temporary access to the tab a user is working in. It is granted in response to an explicit user action, such as clicking the extension's toolbar button. Access is limited to that tab and lasts until the user navigates elsewhere.
Its purpose is to enable extensions to fulfill the common use case of "do something to the current page when the user asks", without the extension needing broad privileges. For example, consider an extension that wants to run a script in the current page when the user clicks its toolbar button. Without activeTab, the extension would have to request the host permission <all_urls>, which gives it far more power than it needs: the ability to execute scripts in any tab, at any time, rather than in the active tab only and only in response to a user action.
Because activeTab provides limited access, browsers don't display a permission warning when the user installs the extension.
Request the activeTab permission
Your extension requests activeTab using the permissions manifest key:
"permissions": ["activeTab"]
activeTab is an API permission, not a host permission.
It's also possible to include activeTab in optional_permissions and request it at runtime using permissions.request(). It's one of the permissions granted silently, without a user prompt.
Note:
activeTab grants privileges for a tab. It doesn't, by itself, grant access to an API. For example, to inject a script, your extension needs the "scripting" permission to use the scripting API.
How activeTab is granted
The browser grants activeTab when the user interacts with the extension. These interactions are known as user actions and include the user:
- clicking the extension's toolbar button or page action.
- selecting an extension's context menu item, which triggers the
menus.onClickedevent. - activating a keyboard shortcut defined by the extension with the
commandsAPI, which triggers thecommands.onCommandevent. - clicking an extension suggestion in the address bar (omnibox), which triggers the
omnibox.onInputEnteredevent (from Firefox 142).
Usually, the tab granted activeTab is the active tab. There is one exception: an extension can use the menus API to create a menu item that displays when the user context-clicks a tab in the tab strip. If the user selects this menu item, activeTab is granted for the tab clicked, even if it isn't the active tab.
What activeTab grants
While activeTab is granted for a tab, the extension can:
- Inject JavaScript or CSS into the tab, using the
scriptingAPI (ortabs.executeScript()andtabs.insertCSS()in Manifest V2). See Loading content scripts. - Read the privileged properties of the tab's
tabs.Tabobject:url,title, andfavIconUrl. Otherwise, these properties require the"tabs"permission or a matching host permission. - Capture the tab's contents with
tabs.captureVisibleTab()(from Firefox 126). - Read the rules matched for the tab with
declarativeNetRequest.getMatchedRules(), without the"declarativeNetRequestFeedback"permission.
Scope of the access
activeTab grants scripting access to the top-level page in the tab and to same-origin frames within it. Running scripts or modifying styles inside cross-origin frames requires additional host permissions.
The restrictions and limitations that apply to particular sites and URI schemes also apply to activeTab. Some special pages don't allow script injection, including reader view, view-source, the PDF viewer, and other built-in browser UI pages.
When the access ends
The extension can only access the tab, or the data, that existed when the user interaction occurred. When the tab navigates away, the extension loses permission to access it. This means that the extension must complete its work with the tab, or capture the data it needs, during the granted period. If the extension needs access again, the user must repeat the user action.
The point at which access ends varies by browser browser_compatibility.
Example
This extension injects a script into the current page when the user clicks its toolbar button. It needs no host permissions.
manifest.json:
{
"manifest_version": 3,
"name": "Heading highlighter",
"version": "1.0",
"permissions": ["activeTab", "scripting"],
"action": {
"default_title": "Highlight headings"
},
"background": {
"scripts": ["background.js"]
}
}
background.js:
function highlightHeadings() {
for (const heading of document.querySelectorAll("h1, h2, h3")) {
heading.style.backgroundColor = "yellow";
}
}
browser.action.onClicked.addListener((tab) => {
// activeTab is granted for `tab` because the user clicked the toolbar button.
browser.scripting.executeScript({
target: { tabId: tab.id },
func: highlightHeadings,
});
});
The same click also makes the privileged tab properties readable, so tab.url and tab.title hold real values rather than being undefined.
Further examples
These further examples showing the use of declare the activeTab permission are available in the repository of example extensions at https://github.com/mdn/webextensions-examples. :
| Example | How activeTab is used |
|---|---|
| apply-css |
A page action click grants access to inject or remove CSS on the active
tab (tabs.insertCSS() and tabs.removeCSS()).
|
| beastify |
A browser action click grants access for
scripting.executeScript() and scripting.insertCSS()
on the active tab.
|
| context-menu-copy-link-with-types | A context menu click on a link unlocks access to the page so the link can be copied to the clipboard. |
| history-deleter | Reads the active tab's URL to determine the domain whose history is to be deleted. |
| menu-demo | A menu item click unlock the active tab for the menu manipulation demo. |
| menu-remove-element | A menu item click unlocks page access to inject a script that removes the element under the cursor. |
Browser compatibility
Firefox, Safari, and Chromium-based browsers, including Chrome and Edge, support activeTab. However, when it's granted, what it enables, and when it's revoked vary.
Actions that grant activeTab
| User action | Chrome | Firefox | Safari |
|---|---|---|---|
| Clicking the extension's toolbar button | Yes | Yes | Yes |
| Selecting the extension's context menu item | Yes | Yes | Yes |
| Activating the extension's keyboard shortcut | Yes | From Firefox 63 | Yes |
| Accepting an address bar (omnibox) suggestion | Yes | From Firefox 142 | No, Safari doesn't support the omnibox API |
| Selecting a menu item on a tab in the tab strip | From Chrome 150 | From Firefox 63 | No, Safari doesn't support the tab value of menus.ContextType |
Capabilities granted
| Capability | Chrome | Firefox | Safari |
|---|---|---|---|
| Programmatic script and stylesheet injection | Yes | Yes | Yes |
Sensitive tabs.Tab properties (url, title, favIconUrl) |
Yes | Yes | Yes |
tabs.captureVisibleTab() |
Yes | From Firefox 126 | Yes |
Intercepting the tab's network requests with the webRequest and declarativeNetRequest APIs |
Yes, for the tab's main frame origin | No (Firefox bug 1617479) | Unknown |
Also, the access browsers grant with activeTab differs:
- Firefox and Safari grant access to the active tab only.
- Chrome grants the host permissions derived from the tab's URL.
Chrome's logic can provide more access than Firefox's, for example:
- Another tab with the same origin can be scripted in Chrome, but not in Firefox.
- An extension script (such as a background script or a popup's script) can make a cross-origin request to the tab's URL in Chrome, but not in Firefox.
- The
cookiesAPI requires host permissions to access cookies for specific domains. Chrome allows this withactiveTab, while Firefox doesn't.
This list isn't exhaustive.
When access is revoked
In all browsers, closing the tab revokes access. However, same-document navigations, such as a fragment (hash) change or a History.pushState() call, don't: the document and its origin are unchanged, so access is preserved.
For navigations that load a new document, the behavior differs:
- Chrome: access persists while the tab stays on the same origin, including across reloads. It's revoked when the tab navigates to a different origin.
- Safari: access persists while the tab stays on the same host, including across reloads. It's revoked when the tab navigates to a different host.
- Firefox: access is tied to the document that was in the tab when the user action occurred. Loading a new document, including on a reload or a same-origin navigation, ends the access, and the user must repeat the user action. If that document returns from the back/forward cache, its access is restored.
Other differences
- Permission prompts: Firefox and Chrome grant an extension's requested host permissions on installation, so
activeTabavoids an install-time warning. Safari, by contrast, defaults host permissions to "ask", and prompts the user the first time the extension tries to access a site, offering Allow for One Day or Always Allow. UsingactiveTabavoids this prompt, as Safari treats the user's interaction with the extension as the grant. - Manifest V2 and V3:
activeTabworks the same way in both manifest versions in all browsers except that in Firefox Manifest V3activeTabdoesn't enablescripting.executeScriptin an iframe with a different origin (see Bug 1839200). In Manifest V3, thescriptingAPI replacestabs.executeScript()andtabs.insertCSS(), and the"scripting"permission is needed alongsideactiveTab.
See also
permissionsmanifest keyoptional_permissionsmanifest key- User actions
- Content scripts
- Request the right permissions on Extension Workshop
- The "activeTab" permission in the Chrome extensions documentation