Chrome incompatibilities

Extensions built with WebExtension APIs are designed to be compatible with Chrome and Opera extensions. As far as possible, extensions written for those browsers should run on Firefox with minimal changes.

However, there are significant differences between Chrome, Firefox, and Edge. In particular:

  • Support for JavaScript APIs differs across browsers. See Browser support for JavaScript APIs 了解更多细节。
  • 支持 manifest.json keys differs across browsers. See the "Browser compatibility" section manifest.json page for more details.
  • Javascript APIs:
    • In Firefox and Edge: JavaScript APIs are accessed under the 浏览器 名称空间。
    • In Chrome: JavaScript APIs are accessed under the chrome namespace. (cf. Chrome bug 798169 )
  • Asynchronous APIs:
    • In Firefox: Asynchronous APIs are implemented using promises.
    • In Chrome and Edge: Asynchronous APIs are implemented using callbacks. (cf. Chrome bug 328932 )

The rest of this page summarizes these and other incompatibilities.

JavaScript API

chrome.* and browser.* namespace

  • In Firefox: The equivalent APIs are accessed using the 浏览器 名称空间。
    browser.browserAction.setIcon({path: "path/to/icon.png"});
    
    							
  • In Chrome: Extensions access privileged JavaScript APIs using the chrome 名称空间。
    chrome.browserAction.setIcon({path: "path/to/icon.png"});
    
    							

Callbacks and promises

  • In Firefox: Asynchronous APIs use promises to return values instead.
    function logCookie(c) {
      console.log(c);
    }
    function logError(e) {
      console.error(e);
    }
    let setCookie = browser.cookies.set(
      {url: "https://developer.mozilla.org/"}
    );
    setCookie.then(logCookie, logError);
    
    							
  • In Chrome: Asynchronous APIs use callbacks to return values, and runtime.lastError to communicate errors.
    function logCookie(c) {
      if (chrome.runtime.lastError) {
        console.error(chrome.runtime.lastError);
      } else {
        console.log(c);
      }
    }
    chrome.cookies.set(
      {url: "https://developer.mozilla.org/"},
      logCookie
    );
    
    							

Firefox supports both the chrome and 浏览器 名称空间

As a porting aid, the Firefox implementation of WebExtensions supports chrome , using callbacks, as well as 浏览器 , using promises. This means that many Chrome extensions will just work in Firefox without any changes.

注意: However, this is not part of the WebExtensions standard. and may not be supported by all compliant browsers.

If you choose to write your extension to use 浏览器 and promises, then Firefox also provides a polyfill that will enable it to run in Chrome: https://github.com/mozilla/webextension-polyfill .

Partially supported APIs

The page Browser support for JavaScript APIs includes compatibility tables for all APIs that have any support in Firefox. Where there are caveats around support for a given API item, this is indicated in these tables with an asterisk "*" and in the reference page for the API item, the caveats are explained.

These tables are generated from compatibility data stored as JSON files in GitHub .

The rest of this section describes compatibility issues that are not already captured in the tables.

Notifications API

For notifications.create() ,采用 type "basic" :

  • In Firefox : iconUrl is optional.
  • In Chrome : iconUrl 被要求。

When the user clicks on a notification:

  • In Firefox : The notification is cleared immediately.
  • In Chrome : This is not the case.

若调用 notifications.create() more than once in rapid succession:

  • In Firefox : In Firefox, the notifications may not display at all. Waiting to make subsequent calls until within the chrome.notifications.create() callback function is not a sufficient delay to prevent this.

Proxy API

Firefox's proxy API followed a completely different design from Chrome's Proxy API.

  • In Firefox : An extension can register a PAC file.
  • In Chrome : An extension can register a PAC file, but can also define explicit proxying rules.

Because this API is incompatible with Chrome's proxy API, the Firefox proxy API is only available through the 浏览器 名称空间。

Tabs API

当使用 tabs.executeScript() or tabs.insertCSS() :

  • In Firefox : Relative URLs passed are resolved relative to the current page URL.
  • In Chrome : These URLs are resolved relative to the extension's base URL.

To work cross-browser, you can specify the path as an absolute URL, starting at the extension's root, like this:

/path/to/script.js
					

When querying tabs by URL tabs.query() :

  • In Firefox : Extensions must have the "tabs" permission.
  • In Chrome : Extensions do not need the "tabs" permission, but only tabs whose URLs match the extension's host permissions will be included in the results.

When calling tabs.remove() :

  • In Firefox tabs.remove() promise is fulfilled after the beforeunload 事件。
  • In Chrome : The callback does not wait for beforeunload .

WebRequest API

  • In Firefox:
    • Requests can be redirected only if their original URL uses the http: or https: 方案。
    • activeTab permission does not allow intercepting network requests in the current tab. (See bug 1617479 )
    • Events are not fired for system requests (for example, extension upgrades or searchbar suggestions).
    • If an extension wants to redirect a public (e.g., HTTPS) URL to an extension page , the extension's manifest.json file must contain a web_accessible_resources key with the URL of the extension page.
      • 注意: 任何 website may then link or redirect to that URL, and extensions should treat any input (POST data, for example) as if it came from an untrusted source, just as a normal web page should.

    • Some of the browser.webRequest.* APIs allow returning Promises that resolves webRequest.BlockingResponse asynchronously.
  • In Chrome: webRequest.onAuthRequired supports asynchronous webRequest.BlockingResponse via supplying 'asyncBlocking' .

Windows API

  • In Firefox: onFocusChanged windows API, will trigger multiple times for a given focus change.

Unsupported APIs

DeclarativeContent API

Miscellaneous incompatibilities

URLs in CSS

  • In Firefox: URLs in injected CSS files are resolved relative to the CSS file itself .
  • In Chrome: URLs in injected CSS files are resolved relative to the page they are injected into .

Support for dialogs in background pages

web_accessible_resources

  • In Firefox: Resources are assigned a random UUID that changes for every instance of Firefox: moz-extension://«random-UUID»/«path» . This randomness can prevent you from doing a few things, such as add your specific extension's URL to another domain's CSP policy.
  • In Chrome: When a resource is listed in web_accessible_resources , it is accessible as chrome-extension://«your-extension-id»/«path» . The extension ID is fixed for a given extension.

Manifest "key" property

  • In Firefox: Since Firefox uses random UUIDs for web_accessible_resources , this property is unsupported.
  • In Chrome: When working with an unpacked extension, the manifest may include a "key" property to pin the extension ID across different machines. This is mainly useful when working with web_accessible_resources .

Content script HTTP(S) requests

  • In Firefox: When a content script makes an HTTP(S) request, you must provide absolute URLs.
  • In Chrome: When a content script makes a request (for example, using fetch() ) to a relative URL (like /api ), it will be sent to https://example.com/api .

Sharing variables between content scripts

  • In Firefox: You cannot share variables between content scripts by assigning them to this.{variableName} in one script and then attempting to access them using window.{variableName} in another. This is a limitation created by the sandbox environment in Firefox. This limitation may be removed, see bug 1208775 .

Content script lifecycle during navigation

  • In Firefox: Content scripts remain injected in a web page after the user has navigated away, however, window object properties are destroyed. For example, if a content script sets window.prop1 = "prop" and the user then navigates away and returns to the page window.prop1 is undefined. This issue is tracked in bug 1525400 . To mimic the behavior of Chrome, listen for the pageshow and pagehide events. Then simulate the injection or destruction of the content script.
  • In Chrome: Content scripts are destroyed when the user navigates away from a web page. If the user then returns to the page through history, by clicking the back button, the content script is injected into the web page again.

"per-tab" zoom behavior

  • In Firefox: The zoom level persists across page loads and navigation within the tab.
  • In Chrome: Zoom changes are reset on navigation; navigating a tab will always load pages with their per-origin zoom factors.

tabs.ZoomSettingsScope .

manifest.json keys

The main manifest.json page includes a table describing browser support for manifest.json keys. Where there are caveats around support for a given key, this is indicated in the table with an asterisk "*" and in the reference page for the key, the caveats are explained.

These tables are generated from compatibility data stored as JSON files in GitHub .

Native messaging

Connection-based messaging arguments

On Linux and Mac: Chrome passes one argument to the native app, which is the origin of the extension that started it, in the form: chrome-extension://«extensionID/» (trailing slash required). This enables the app to identify the extension.

在 Windows: Chrome passes two arguments:

  1. The origin of the extension
  2. A handle to the Chrome native window that started the app

allowed_extensions

  • In Firefox: The manifest key is called allowed_extensions .
  • In Chrome: The manifest key is called allowed_origins 代替。

App manifest location

Data cloning algorithm

Some extension APIs allow an extension to send data from one part of the extension to another, such as runtime.sendMessage() , tabs.sendMessage() , runtime.onMessage postMessage() 方法为 runtime.port ,和 tabs.executeScript() .

The Structured clone algorithm supports more types than the JSON serialization algorithm. A notable exception are (DOM) objects with a toJSON method. DOM objects are not cloneable nor JSON-serializable by default, but with a toJSON() method, these can be JSON-serialized (but still not cloned with the structured cloning algorithm). Examples of JSON-serializable objects that are not structured cloneable include instances of URL and PerformanceEntry .

Extension that rely on the toJSON() method of the JSON serialization algorithm can use JSON.stringify() followed by JSON.parse() to ensure that a message can be exchanged, because a parsed JSON value is always structurally cloneable.

Found a problem with this page?

最后修改: , 由 MDN 贡献者

  1. 浏览器扩展名
  2. 快速入门
    1. What are extensions?
    2. Your first extension
    3. Your second extension
    4. Anatomy of an extension
    5. Example extensions
    6. What next?
  3. 概念
    1. Using the JavaScript APIs
    2. Content scripts
    3. Match patterns
    4. Working with files
    5. 国际化
    6. Content Security Policy
    7. Native messaging
    8. Differences between API implementations
    9. Chrome incompatibilities
  4. 用户界面
    1. 用户界面
    2. Toolbar button
    3. Address bar button
    4. Sidebars
    5. Context menu items
    6. Options page
    7. Extension pages
    8. Notifications
    9. Address bar suggestions
    10. Developer tools panels
  5. 如何
    1. Intercept HTTP requests
    2. Modify a web page
    3. Insert external content
    4. Share objects with page scripts
    5. Add a button to the toolbar
    6. Implement a settings page
    7. Work with the Tabs API
    8. Work with the Bookmarks API
    9. Work with the Cookies API
    10. Work with contextual identities
    11. Interact with the clipboard
    12. Build a cross-browser extension
  6. Firefox differentiators
  7. JavaScript API
    1. Browser support for JavaScript APIs
    2. alarms
    3. bookmarks
    4. browserAction
    5. browserSettings
    6. browsingData
    7. captivePortal
    8. clipboard
    9. 命令
    10. contentScripts
    11. contextualIdentities
    12. Cookie
    13. devtools
    14. dns
    15. downloads
    16. events
    17. extension
    18. extensionTypes
    19. find
    20. history
    21. i18n
    22. identity
    23. idle
    24. management
    25. menus
    26. notifications
    27. omnibox
    28. pageAction
    29. permissions
    30. pkcs11
    31. privacy
    32. proxy
    33. runtime
    34. search
    35. sessions
    36. sidebarAction
    37. storage
    38. tabs
    39. theme
    40. topSites
    41. 类型
    42. userScripts
    43. webNavigation
    44. webRequest
    45. windows
  8. Manifest keys
    1. 介绍
    1. 作者
    2. background
    3. browser_action
    4. browser_specific_settings
    5. chrome_settings_overrides
    6. chrome_url_overrides
    7. 命令
    8. content_scripts
    9. content_security_policy
    10. default_locale
    11. description
    12. developer
    13. devtools_page
    14. dictionaries
    15. externally_connectable
    16. homepage_url
    17. icons
    18. incognito
    19. manifest_version
    20. name
    21. offline_enabled
    22. omnibox
    23. optional_permissions
    24. options_page
    25. options_ui
    26. page_action
    27. permissions
    28. protocol_handlers
    29. short_name
    30. sidebar_action
    31. storage
    32. theme
    33. theme_experiment
    34. user_scripts
    35. version
    36. version_name
    37. web_accessible_resources
  9. Extension Workshop
    1. Develop
    2. Publish
    3. Manage
    4. Enterprise
  10. Contact us
  11. Channels
    1. Add-ons blog
    2. Add-ons forum
    3. Add-ons chat