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.
See theDeveloping extensions for Firefox for Android page for additional guidance if you plan to support Firefox for Android.
What is Manifest V3?
Manifest V3 (MV3) is the umbrella term for several foundational changes to the WebExtensions API in Firefox. The name refers to the declaredmanifest_version
key in each extension’smanifest.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.
Manifest V3 changes
This section details the Manifest V3 changes made to Firefox.
Manifest version
The manifest.json keymanifest_version
accepts3
. To use Manifest V3, update your manifest.json file like this:
"manifest_version":3
Search extensions icons
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.jsonchrome_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
In Manifest V2, host permissions are defined in the manifest.json keyspermissions
oroptional_permissions
. The host permissions defined in the manifest.json keyspermissions
are displayed to the user on installation and granted to the extension permanently.
In Manifest V3, host permissions are defined in thehost_permissions
andoptional_host_permissions
keys. With Manifest V3 extensions, users can grant or revoke any host permissions on an ad hoc basis.
Up to Firefox 126, Manifest V3 host permissions were not granted on installation and were not displayed to the user. From Firefox 127, host permissions listed inhost_permissions
andcontent_scripts
are displayed in the install prompt and granted on installation. However, if an extension update grants new host permissions, these are not shown to the user (seeFirefox bug 1893232).
As users can revoke host permissions, your extension should check for the availability of any expected host permissions and request them if necessary.
SeeRequested permissions and user prompts in thehost_permissions
documentation for more information.
Move all host permission specifications to the manifest.json keyhost_permissions
like this:
"permissions":["tabs","notifications"],"optional_permissions":["geolocation"],"host_permissions":["http://www.mysite.com/","*://*.example.org/*"]
Browser action
The features available under the manifest.json keybrowser_action
and thebrowserAction
API have moved to a newaction
key andAPI. 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:
- rename the manifest.json key 'browser_action' to 'action' and remove any reference to
browser_style
, like this:"action":{"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}]}
- update API references from
browser.browserAction
tobrowser.action
. - if used, change
_execute_browser_action
to_execute_action
in thecommands
manifest key and in themenu.create
andmenu.update
API methods (or their aliasescontextMenus.create
andcontextMenus.update
).
If the user changes the shortcut of the_execute_browser_action
command, it is automatically carried over to the_execute_action
command when an extension migrates from Manifest V2 to V3. This was implemented in Chrome 111 and Firefox 127.
In Chromium and Safari, the Browser Action and Page Action APIs are unified into the Action API,page_action
is merged into the renamedaction
key, and the_execute_page_action
special shortcut is replaced by_execute_action
. Firefox retains the page action API, key, and special shortcut.
browser_style
In Manifest Version 3,browser_style: true
is no longer supported in theoptions_ui,action,page_action, andsidebar_action manifest keys.
The goal of this property was to enable extension UI components to take on the browser's style. However, it only partially worked as intended. As a consequence, it has been deprecated for Manifest V3. Therefore, remove any references from the manifest keys.
In Manifest Version 2,browser_style
defaults totrue
foroptions_ui
andsidebar_action
. Therefore, unless you had set"browser_style": false
, confirm that the appearance ofoptions_ui
andsidebar_action
match your intended design.
SeeManifest V3 migration forbrowser_style
for more information.
Scripting API
TheScripting API takes over the features oftabs.insertCSS()
,tabs.removeCSS()
, andtabs.executeScript()
and adds capabilities to register, update, and unregister content scripts at runtime.
Also, thecode
parameter is removed so that arbitrary strings can no longer be executed. This API requires thescripting
permission. So, you need to move any arbitrary strings executed as scripts to files and rewrite your code to use the Scripting API.
Event-driven background scripts
Firefox has extended support forbackground 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:
- Update your manifest.json
background
key to remove the"persistent"
property or set it tofalse
. This feature is also supported in MV2 from Firefox 106. - Ensure listeners are at the top-level and use the synchronous pattern.
- Record state changes in local storage.
- Change timers to alarms.
- Switch from using
extension.getBackgroundPage
to call a function from the background page, toruntime.getBackgroundPage
. - Place menu creation using
menus.create
or its aliascontextMenus.create
in aruntime.onInstalled
listener. Also, note that themenus.onClicked
event or its aliascontextMenus.onClicked
must be used to handle menu entry click events from an event page, instead of theonclick
parameter of thecontextMenus.create
orcontextMenus.update
methods. If theonclick
property ofmenus.create
or its aliascontextMenus.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 thebackground script page on MDN.
Event pages and backward-compatibility
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 inruntime.onInstalled
is followed, these menus are removed after a browser restart in Firefox 105 and earlier. To work around this issue, you could unconditionally callbrowser.contextMenus.create
. When the menu exists, thebrowser.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., withruntime.onInstalled
orruntime.onStartup
).
You can detect the availability of event pages using the characteristic that an error is thrown synchronously whenonclick
is passed tocontextMenus.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.}asyncfunctionregisterMyMenus(){ browser.contextMenus.create({id:"my-menu",/* etc. */});}if(eventPagesSupported){ browser.runtime.onInstalled.addListener(registerMyMenus);}else{registerMyMenus();}
Content security policies
Content security policy (CSP) in thecontent_security_policy
manifest.json key is changing to use theextension_pages
property.
Therefore, you need to move the extension’s CSP to the manifest.json key toextension_pages
, like this:
"content_security_policy":{"extension_pages":"default-src 'self'"}
Manifest V3 has a more restrictive content security policy than Manifest V2, this may require further changes in your pages.
Mozilla’s long-standingadd-on policies prohibit remote code execution. In keeping with these policies, thecontent_security_policy field no longer supports sources permitting remote code in script-related directives, such asscript-src
or’unsafe-eval’
. The only permitted values for thescript-src
directive are’self’
and’wasm-unsafe-eval’
.’wasm-unsafe-eval’
must be specified in the CSP if an extension is to use WebAssembly. In Manifest V3, content scripts are subject to the same CSP as other parts of the extension.
Historically, a custom extension CSP requiredobject-src
to be specified. This is not required in Manifest V3 (and was removed from Manifest V2 in Firefox 106). Seeobject-src
in thecontent_security_policy
documentation). This change makes it easier for extensions to customize the CSP with minimal boilerplate.
Web Accessible Resources
Web accessible resources are available only to the sites and extensions specified in the manifest. In Manifest V3, Firefox supports theextension_ids
,matches
, andresources
properties to specify the packaged resources you want to make available. Firefox does not support theuse_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.
Features already supported by Firefox
As part of its Manifest V3 implementation, Chromium introducespromise 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 thebrowser.*
namespace.
In Manifest v2, Firefox extensions support the use of thechrome.*
namespace with APIs that provide asynchronous event handling using callbacks. In Manifest V3, Firefox supports promises for asynchronous events in thechrome.*
namespace.
Extension version in the manifest
The format of the top-level manifest.jsonversion
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, but0.2
,2.0.1
, and2.1
are allowed).
Migration checklist
- Update the manifest.json key
manifest_version
to3
. - If your extension adds a search engine, add a local icon and reference it in the manifest.json key
chrome_settings_overrides.search_provider.favicon_url
. - Remove any host permissions from the manifest.json keys
permissions
andoptional_permissions
and add them to thehost_permissions
key. Remember thathost_permissions
is treated as an optional permission in Firefox and Safari but granted at install in Chrome. - Remove references to
browser_style
from the manifest.json keysbrowser_action
,options_ui
,page_action
, andsidebar_action
. - If
browser_style:false
was not specified inoptions_ui
andsidebar_action
, confirm that their appearance has not changed. - Rename the manifest.json key
browser_action
toaction
and update any API references frombrowser.browserAction
tobrowser.action
. - Convert background pages to be non-persistent.
- Move the extension’s CSP to the manifest.json key
content_security_policy.extension_pages
and update the CSP to conform to Manifest V3 requirements. - Move any arbitrary strings executed as scripts to files and update your code to use the Scripting API.
- Rename the deprecated manifest.json key
applications
tobrowser_specific_settings
. - The add-on ID is required to publish your extension. Make sure to add one in the manifest.json key
browser_specific_settings.gecko.id
. - Ensure that the top-level manifest.json key
version
is a string of numbers separated by up to 3 dots. For details, seeversion format.
Tags: webextensions api firefox
Contributors: erosman Klestofer rebloor willdurand
Last update: rebloor
Up Next
Develop
Browser compatibility
Develop
Browser Extension Development Tools
Develop