Manifest V3 migration guide
Manifest V3 became generally available in Firefox 109 after being available as a developer preview from Firefox 101. This page details what's changed and how you adapt your extensions to take advantage of Manifest V3.
Manifest V3 became generally available in Firefox 109 after being available as a developer preview from Firefox 101. This page details what's changed and how you adapt your extensions to take advantage of Manifest V3.
Manifest v3 (MV3) is the umbrella term for several foundational changes to the WebExtensions API in Firefox. The name refers to the declared manifest_version
key in each extension’s manifest.json file.
The Manifest v3 changes apply to extensions for Safari, Firefox, and Chromium-based browsers – such as Chrome, Edge, and Opera. While the goal is to maintain a high degree of compatibility between the Firefox, Safari, and Chromium extension platforms, our implementation diverges where we think it matters and where our values point to a different direction.
This article discusses the changes introduced with Manifest v3 in Firefox and highlights where they diverge from the Chrome and Safari implementation.
This section details the Manifest V3 changes made to Firefox.
The manifest.json key manifest_version
accepts 3
. To use Manifest V3, update your manifest.json file like this:
"manifest_version": 3
Search extensions must use local icons. This change prevents the unnecessary network pings that result from accessing remote icons.
To accommodate this change, provide a local icon and define it in your manifest.json chrome_settings_overrides manifest key like this:
"chrome_settings_overrides": {
"search_provider": {
"name": "Search engine",
"search_url": "https://www.searchengine.com/search/?q={searchTerms}",
"keyword": "search",
"favicon_url": "/imager/favicon.ico"
}
}
Host permissions are no longer defined in the manifest.json keys permissions
or optional_permissions
. Instead, they are defined in the host_permissions
key.
Move all host permission specifications to the manifest.json key host_permissions
like this:
"permissions": [
"tabs",
"notifications"
],
"optional_permissions": [
"geolocation"
],
"host_permissions": [
"http://www.mysite.com/",
"*://*.example.org/*"
]
The features available under the manifest.json key browser_action
and the browserAction
API have moved to a new action
key and API. Also, the _execute_action
special shortcut is introduced.
As the old and new key and API are otherwise identical, the changes needed are relatively straightforward and are as follows:
"action": {
"browser_style": true,
"default_icon": {
"16": "button/geo-16.png",
"32": "button/geo-32.png"
},
"default_title": "Whereami?",
"default_popup": "popup/geo.html",
"theme_icons": [{
"light": "icons/geo-16-light.png",
"dark": "icons/geo-16.png",
"size": 16
}, {
"light": "icons/geo-32-light.png",
"dark": "icons/geo-32.png",
"size": 32
}]
}
browser.browserAction
to browser.action
._execute_browser_action
to _execute_action
in the commands
manifest key and in the menu.create
and menu.update
API methods (or their aliases contextMenus.create
and contextMenus.update
).In Chromium and Safari, the Browser Action and Page Action APIs are unified into the Action API, page_action
is merged into the renamed action
key, and the _execute_page_action
special shortcut is replaced by _execute_action
. Firefox retains the page action API, key, and special shortcut in the developer preview but will merge the page action features into action in a later release.
The Scripting API takes over the features of tabs.insertCSS()
, tabs.removeCSS()
, and tabs.executeScript()
and adds capabilities to register, update, and unregister content scripts at runtime.
Also, the code
parameter is removed so that arbitrary strings can no longer be executed. This API requires the scripting
permission. So, you need to move any arbitrary strings executed as scripts to files and rewrite your code to use the Scripting API.
Firefox has extended support for background scripts by enabling non-persistent background pages (aka Event Pages) for Manifest V2 and V3. Using non-persistent background scripts greatly reduces your extension use of browser resources. However, MV3 removes support for persistent background pages.
To migrate your extension to using non-persistent background pages, you need to:
background
key to remove the "persistent"
property or set it to false
. This feature is also supported in MV2 from Firefox 106.extension.getBackgroundPage
to call a function from the background page, to runtime.getBackgroundPage
.menus.create
or its alias contextMenus.create
in a runtime.onInstalled
listener. Also, note that the menus.onClicked
event or its alias contextMenus.onClicked
must be used to handle menu entry click events from an event page, instead of the onclick
parameter of the contextMenus.create
or contextMenus.update
methods. If the onclick
property of menus.create
or its alias contextMenus.create
are used from a call originating from an event page, they throw synchronously.Safari also supports event-driven background scripts, however, Chromium has adopted service workers instead.
Firefox supports non-persistent background pages from Firefox 106. In Firefox 105 and earlier, event pages are run as if they are a persistent background page.
More information on the migration process can be found on the background script page on MDN.
This section is only relevant if your extension supports Firefox 105 and earlier.
An extension designed as a non-persistent background page works even when event pages are not supported (i.e., in Firefox 105 and earlier) with one exception: the registration of context menus. In an event page, context menus persist across restarts, while they do not in persistent background pages.
If the recommendation to register menus in runtime.onInstalled
is followed, these menus are removed after a browser restart in Firefox 105 and earlier. To work around this issue, you could unconditionally call browser.contextMenus.create
. When the menu exists, the browser.runtime.lastError
property is set when the (optional) create
callback is called.
browser.contextMenus.create(
{
id: "my-menu",
// etc.
},
() => {
// TODO: Do not forget to read the "browser.runtime.lastError" property to
// avoid warnings about an uncaught error when the menu item was created
// before ("ID already exists: my-menu").
}
);
If the initialization of the menu is expensive or requires complex logic, an alternative is to check whether event pages are supported and, if so, run the logic less frequently than at every wakeup of the event page (e.g., with runtime.onInstalled
or runtime.onStartup
).
You can detect the availability of event pages using the characteristic that an error is thrown synchronously when onclick
is passed to contextMenus.create
in an event page.
The following code shows how to use such a test to register menus.
let eventPagesSupported = true;
try {
// Firefox throws a synchronous error when onclick is passed in an event page.
browser.contextMenus.create({ id: "test-menu", onclick: () => {} });
eventPagesSupported = false;
browser.contextMenus.remove("test-menu");
} catch (err) {
// Firefox 106+ error: Property "onclick" cannot be used in menus.create, replace with an "onClicked" event listener.
}
async function registerMyMenus() {
browser.contextMenus.create({ id: "my-menu", /* etc. */ });
}
if (eventPagesSupported) {
browser.runtime.onInstalled.addListener(registerMyMenus);
} else {
registerMyMenus();
}
Content security policy (CSP) in the manifest.json key is changing to use the extension_pages
property. Manifest V3 has a more restrictive content security policy than Manifest V2, this may require further changes in your pages.
Move the extension’s CSP to the manifest.json key to extension_pages
, like this:
"content_security_policy": {
"extension_pages": "default-src 'self'"
}
Web accessible resources are available only to the sites and extensions specified in the manifest. In Manifest V3, Firefox supports the extension_ids
, matches
, and resources
properties to specify the packaged resources you want to make available. Firefox does not support the use_dynamic_url
property.
To migrate your extension, rewrite the manifest.json key ‘web_accessible_resources’ to specify the sites and extensions that can access the resources.
As part of its Manifest V3 implementation, Chromium introduces promise support to many methods with the goal of eventually supporting promises on all appropriate methods. This will provide for greater compatibility between Firefox and Chrome extensions, given that Firefox already supports promises when using the browser.*
namespace.
In Manifest v2, Firefox extensions support the use of the chrome.*
namespace with APIs that provide asynchronous event handling using callbacks. In Manifest v3, Firefox supports promises for asynchronous events in the chrome.*
namespace.
The format of the top-level manifest.json version
key in Firefox has evolved and became simpler: letters and other previously allowed symbols are no longer accepted. The value must be a string with 1 to 4 numbers separated by dots (e.g., 1.2.3.4
). Each number can have up to 9 digits and leading zeros before another digit are not allowed (e.g., 2.01
is forbidden, but 0.2
, 2.0.1
, and 2.1
are allowed).
manifest_version
to 3
.chrome_settings_overrides.search_provider.favicon_url
.permissions
and optional_permissions
and add them to the host_permissions
key.browser_action
to action
and update any API references from browser.browserAction
to browser.action
.content_security_policy.extension_pages
and update the CSP to conform to Manifest V3 requirements.applications
to browser_specific_settings
.browser_specific_settings.gecko.id
.version
is a string of numbers separated by up to 3 dots. For details, see version format.Develop
Develop
Develop