Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 72 additions & 15 deletions src/content/documentation/develop/manifest-v3-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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": {
Expand All @@ -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.
Expand Down Expand Up @@ -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.

Expand All @@ -223,21 +223,37 @@ 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:

- Update your manifest.json `background` key to remove the `"persistent"` property or set it to `false`. 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`](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).
- 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.
- 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` 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
Expand All @@ -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.

Expand Down Expand Up @@ -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.
Expand All @@ -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 %}
Expand Down Expand Up @@ -368,11 +401,28 @@ In Manifest v2, Firefox extensions support the use of the `chrome.*` namespace w

{% capture content %}

### 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/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"
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
Expand All @@ -384,17 +434,24 @@ 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`.
- 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"
Expand Down