From 68ab353b472af36ec5cdef76242808c2179dbae9 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Tue, 27 Jan 2026 06:32:40 +1300 Subject: [PATCH 1/4] Update MV3 migration advice --- .../develop/manifest-v3-migration-guide.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/documentation/develop/manifest-v3-migration-guide.md b/src/content/documentation/develop/manifest-v3-migration-guide.md index dc0866b52..6324383cd 100644 --- a/src/content/documentation/develop/manifest-v3-migration-guide.md +++ b/src/content/documentation/develop/manifest-v3-migration-guide.md @@ -112,13 +112,13 @@ To accommodate this change, provide a local icon and define it in your manifest. ### Host permissions -In Manifest V2, host permissions are defined in the manifest.json keys `permissions` or `optional_permissions`. The host permissions defined in the manifest.json keys `permissions` are displayed to the user on installation and granted to the extension permanently. +In Manifest V2, an extension requests its host permissions in the manifest.json `permissions` or `optional_permissions` keys. The host permissions defined in the `permissions` key are displayed to the user on installation and granted to the extension permanently. -In Manifest V3, host permissions are defined in the [`host_permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions) and [`optional_host_permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_host_permissions) keys. With Manifest V3 extensions, users can grant or revoke any host permissions on an ad hoc basis. +In Manifest V3, host permissions are defined in the [`host_permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions) and [`optional_host_permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_host_permissions) keys. -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 in `host_permissions` and `content_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 (see [Firefox bug 1893232](https://bugzil.la/1893232)). +In Firefox 126 and earlier, Manifest V3 host permissions were not granted during installation and were not displayed to the user. From Firefox 127, host permissions listed in `host_permissions` and `content_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 (see [Firefox bug 1893232](https://bugzil.la/1893232)). -As users can revoke host permissions, your extension should check for the availability of any expected host permissions and request them if necessary. +Users can [grant or revoke any host permission on an ad-hoc basis](https://support.mozilla.org/en-US/kb/manage-optional-permissions-extensions). Therefore, your extension should check whether any required host permissions are available and request them if necessary. See [Requested permissions and user prompts](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions#requested_permissions_and_user_prompts) in the `host_permissions` documentation for more information. @@ -384,7 +384,7 @@ The format of the top-level manifest.json `version` key in Firefox has evolved a - Update the manifest.json key `manifest_version` to `3`. - 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` and `optional_permissions` and add them to the `host_permissions` key. Remember that `host_permissions` is treated as an optional permission in Firefox and Safari but granted at install in Chrome. +- Remove any host permissions from the manifest.json keys `permissions` and `optional_permissions`, and add them to the `host_permissions` and `optional_host_permissions` keys. Remember that users can approve or revoke host permissions at any time, so always check that relevant host permissions are available when needed. - Remove references to `browser_style` from the manifest.json keys `browser_action`, `options_ui`, `page_action`, and `sidebar_action`. - If `browser_style:false` was not specified in `options_ui` and `sidebar_action`, confirm that their appearance has not changed. - Rename the manifest.json key `browser_action` to `action` and update any API references from `browser.browserAction` to `browser.action`. From 367d5e5261d2a70094de79dd77487db961f727d4 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Fri, 30 Jan 2026 07:15:17 +1300 Subject: [PATCH 2/4] Advice regarding extension API features removed --- .../develop/manifest-v3-migration-guide.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/content/documentation/develop/manifest-v3-migration-guide.md b/src/content/documentation/develop/manifest-v3-migration-guide.md index 6324383cd..5f69ce28c 100644 --- a/src/content/documentation/develop/manifest-v3-migration-guide.md +++ b/src/content/documentation/develop/manifest-v3-migration-guide.md @@ -233,7 +233,7 @@ To migrate your extension to using non-persistent background pages, you need to: - 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`](https://developer.mozilla.org/en-US/Mozilla/Add-ons/WebExtensions/API/extension/getBackgroundPage) to call a function from the background page, to [`runtime.getBackgroundPage`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getBackgroundPage). +- Switch from using [`extension.getBackgroundPage`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getBackgroundPage) to call a function from the background page, to [`runtime.getBackgroundPage`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getBackgroundPage). - Place menu creation using [`menus.create`](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/menus/create) or its alias `contextMenus.create` in a `runtime.onInstalled` listener. Also, note that the [`menus.onClicked`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/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. ::: note @@ -368,11 +368,28 @@ In Manifest v2, Firefox extensions support the use of the `chrome.*` namespace w {% capture content %} +### Extension API + +Two features of the `extension` API are deprecated in Manifest V2 and no longer available in Manifest V3, but have alternatives: + +- [`extension.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getURL), use [`runtime.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/lastError) instead. +- [`extension.getURL`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getURL), use [`runtime.getURL`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getURL) instead. + +{% endcapture %} + +{% include modules/one-column.liquid, + id: "removed- apis" + content: content +%} + +{% capture content %} + ### Extension version in the manifest 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). {% endcapture %} + {% include modules/one-column.liquid, id: "extension-version" content: content @@ -393,6 +410,7 @@ The format of the top-level manifest.json `version` key in Firefox has evolved a - 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` to `browser_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`. +- Replace `extension.lastError` with `runtime.lastError` and `extension.getURL` with `runtime.getURL`. - Ensure that the top-level manifest.json key `version` is a string of numbers separated by up to 3 dots. For details, see [version format](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version/format). {% endcapture %} From e3307fff3b468345cda853aa5f1c589bb37a4908 Mon Sep 17 00:00:00 2001 From: rebloor Date: Mon, 2 Feb 2026 04:25:05 +1300 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Rob Wu --- .../documentation/develop/manifest-v3-migration-guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/documentation/develop/manifest-v3-migration-guide.md b/src/content/documentation/develop/manifest-v3-migration-guide.md index 5f69ce28c..b4c7824e7 100644 --- a/src/content/documentation/develop/manifest-v3-migration-guide.md +++ b/src/content/documentation/develop/manifest-v3-migration-guide.md @@ -368,17 +368,17 @@ In Manifest v2, Firefox extensions support the use of the `chrome.*` namespace w {% capture content %} -### Extension API +### Removed APIs Two features of the `extension` API are deprecated in Manifest V2 and no longer available in Manifest V3, but have alternatives: -- [`extension.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getURL), use [`runtime.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/lastError) instead. +- [`extension.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/lastError), use [`runtime.lastError`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/lastError) instead. - [`extension.getURL`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getURL), use [`runtime.getURL`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getURL) instead. {% endcapture %} {% include modules/one-column.liquid, - id: "removed- apis" + id: "removed-apis" content: content %} From bf64f13de233772907628c89fe1e65bfe2f12610 Mon Sep 17 00:00:00 2001 From: Richard Bloor Date: Mon, 2 Feb 2026 05:40:12 +1300 Subject: [PATCH 4/4] Addition of further migration information --- .../develop/manifest-v3-migration-guide.md | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/content/documentation/develop/manifest-v3-migration-guide.md b/src/content/documentation/develop/manifest-v3-migration-guide.md index b4c7824e7..50b64cd82 100644 --- a/src/content/documentation/develop/manifest-v3-migration-guide.md +++ b/src/content/documentation/develop/manifest-v3-migration-guide.md @@ -42,7 +42,7 @@ Manifest V3 (MV3) is the umbrella term for several foundational changes to the W 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 article discusses the changes introduced with Manifest V3 in Firefox and highlights where they diverge from the Chrome and Safari implementations. {% endcapture %} @@ -152,7 +152,7 @@ The features available under the manifest.json key `browser_action` and the `bro 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`](#browser-style), like this: +- Rename the manifest.json key 'browser_action' to 'action' and remove any reference to [`browser_style`](#browser-style), like this: ```json "action": { "default_icon": { @@ -172,8 +172,8 @@ As the old and new key and API are otherwise identical, the changes needed are r }] } ``` -- update API references from `browser.browserAction` to `browser.action`. -- if used, change `_execute_browser_action` to `_execute_action` in the `commands` manifest key and in the [`menu.create`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/create) and [`menu.update`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/update) API methods (or their aliases `contextMenus.create` and `contextMenus.update`). +- Update API references from `browser.browserAction` to `browser.action`. +- If used, change `_execute_browser_action` to `_execute_action` in the `commands` manifest key and in the [`menu.create`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/create) and [`menu.update`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/update) API methods (or their aliases `contextMenus.create` and `contextMenus.update`). ::: note 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. @@ -211,7 +211,7 @@ See [Manifest V3 migration for `browser_style`](https://developer.mozilla.org/en ### Scripting API -The [Scripting API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting) takes over the features of `tabs.insertCSS()`, `tabs.removeCSS()`, and `tabs.executeScript()` and adds capabilities to register, update, and unregister content scripts at runtime. +The [Scripting API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting) 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](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions). So, you need to move any arbitrary strings executed as scripts to files and rewrite your code to use the Scripting API. @@ -223,9 +223,25 @@ Also, the `code` parameter is removed so that arbitrary strings can no longer be {% capture content %} +### userScripts API + +Manifest V3 uses a [userScripts API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts) that is incompatible with the API of the same name available to Manifest MV2 extensions. + +::: note +AMO only approves of the use of the API for user script managers. +::: + +{% endcapture %} +{% include modules/one-column.liquid, + id: "userscripts-api" + content: content +%} + +{% capture content %} + ### Event-driven background scripts -Firefox has extended support for [background scripts](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/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. +Firefox has extended support for [background scripts](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Background_scripts) by enabling non-persistent background pages (aka Event Pages) for Manifest V2 and V3. Using non-persistent background scripts significantly reduces your extension's 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: @@ -234,10 +250,10 @@ To migrate your extension to using non-persistent background pages, you need to: - Record state changes in local storage. - Change timers to alarms. - Switch from using [`extension.getBackgroundPage`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getBackgroundPage) to call a function from the background page, to [`runtime.getBackgroundPage`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getBackgroundPage). -- Place menu creation using [`menus.create`](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/menus/create) or its alias `contextMenus.create` in a `runtime.onInstalled` listener. Also, note that the [`menus.onClicked`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/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. +- Place menu creation using [`menus.create`](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/menus/create) or its alias `contextMenus.create` in a `runtime.onInstalled` listener. Also, note that the [`menus.onClicked`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/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` is used from a call originating from an event page, they throw synchronously. ::: note -Safari also supports event-driven background scripts, however, Chromium has adopted service workers instead. +Safari also supports event-driven background scripts; however, Chromium has adopted service workers instead. ::: ::: note @@ -261,7 +277,7 @@ More information on the migration process can be found on the [background script 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. +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. @@ -314,6 +330,21 @@ if (eventPagesSupported) { {% capture content %} +### XHR and fetch in content scripts + +Cross-origin requests, permitted by extension permissions, using [XHR and fetch](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#xhr_and_fetch) in content scripts are no longer allowed. Instead: +- The destination server should use CORS, or +- The extension has to send a message to the background page (or an extension tab or frame) to ask it to make a request on the content script's behalf. + +{% endcapture %} + +{% include modules/one-column.liquid, + id: "xhr-and-fetch-in-content-scripts" + content: content +%} + +{% capture content %} + ### Content security policies [Content security policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) in the [`content_security_policy`](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy) manifest.json key is changing to use the `extension_pages` property. @@ -330,6 +361,8 @@ Manifest V3 has a more restrictive content security policy than Manifest V2, thi Mozilla’s long-standing [add-on policies](/documentation/publish/add-on-policies/) prohibit remote code execution. In keeping with these policies, the [content_security_policy](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy) field no longer supports sources permitting remote code in script-related directives, such as `script-src` or `’unsafe-eval’`. The only permitted values for the `script-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. +The Manifest V3 CSP also includes `upgrade-insecure-requests` by default. + Historically, a custom extension CSP required `object-src` to be specified. This is not required in Manifest V3 (and was removed from Manifest V2 in Firefox 106). See [`object-src` in the `content_security_policy` documentation](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy#object-src_directive)). This change makes it easier for extensions to customize the CSP with minimal boilerplate. {% endcapture %} @@ -408,11 +441,17 @@ The format of the top-level manifest.json `version` key in Firefox has evolved a - 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. +- Switch to using the new version of the userScripts API. +- Ensure any cross-origin requests using fetch or XHR are sent to servers that implement CORS, or are made via a background page (or an extension tab or frame). - Rename the deprecated manifest.json key `applications` to `browser_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`. - Replace `extension.lastError` with `runtime.lastError` and `extension.getURL` with `runtime.getURL`. - Ensure that the top-level manifest.json key `version` is a string of numbers separated by up to 3 dots. For details, see [version format](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version/format). +::: note +If your extension includes a data collection experience, consider using the [built-in consent for data collection and transmission](/documentation/develop/firefox-builtin-data-consent/). +::: + {% endcapture %} {% include modules/one-column.liquid, id: "migration-checklist"