Making Your Extension Compatible with Both Chrome and Firefox
Tags: javascript, webdev, tips
Published: 2021-03-23 15:07:23

_This article was originally published on [my personal blog](https://blog.shahednasser.com/making-your-extension-compatible-with-both-chrome-and-firefox/)_

Developing extensions for different browsers is mostly similar, however, there are a few differences you should look out for.

This article lists the difference between developing Chrome extensions and Firefox Add-Ons, helping you understand how to make sure your extension is compatible with both browsers. In the end I will also include the difference when packaging and publishing the extensions on the different platforms.

---

## Manifest

Here are the key differences in the `manifest.json` file:

1. Firefox has a `developer` key in the manifest, which is an object that includes `name` and `url`. Chrome doesn't.
2. If you are using the Storage API and want to test your extension in your browser by loading it from your machine, Firefox requires the `browser_specific_settings` key to work, otherwise, the Storage API will not work. An example of it would be:

```json
"browser_specific_settings": {
  "gecko": {
    "id": "addon@example.com",
    "strict_min_version": "42.0"
  }
}
```

### Manifest V3

Currently, Chrome is pushing towards using Manifest V3 which has been controversial for a few reasons. As for Firefox in a [blog post](https://blog.mozilla.org/addons/2019/09/03/mozillas-manifest-v3-faq/) in 2019, Mozilla indicated that they will also support Manifest V3, however, they're not obligated to implement every part of it. Mozilla is intending to keep a lot of functions and APIs that Chrome is discarding in V3.

Suggested Read: [Learn how to migrate your Chrome extension from Manifest V2 to V3!](https://blog.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2/)

---

## API

In Chrome, the API namespace is `chrome.*`, whereas for Firefox it's `browser.*`. Firefox claims that it supports `chrome.*`, but it's preferred to use `browser.*`.

The main difference between the two, however, is that `chrome.*` only supports callbacks when handling asynchronous events, whereas `browser.*` supports both callbacks and promises.

Here's an example of how you'd query tabs in Chrome:

```javascript
chrome.tabs.query({active: true}, function (tabs) {
    console.log(tabs[0].title);
});
```

And here's the same example in Firefox when using Promises:

```javascript
browser.tabs.query({active: true})
    .then ((tabs) => console.log(tabs[0].title))
    .catch ((err) => console.error(err))
```

Mozilla, however, offers a polyfill that allows you to use Promises in all browser extensions. You can check it out [here](https://github.com/mozilla/webextension-polyfill/).

---

## Functions Differences

Some functions have different signatures or behavior for each of the browsers:

1. Chrome states in their `chrome.notifications` [API documentation](https://developer.chrome.com/docs/extensions/reference/notifications/#type-NotificationOptions) that for `chrome.notifications.create` the parameter `iconUrl` is required, whereas for Firefox it's [optional](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/notifications/NotificationOptions).
2. For the tabs API in the functions `insertCSS` and `executeScript`, Firefox resolves the URLs being passed relative to the current page, whereas Chrome resolves the URLs being passed as relative to the root of the extension. To resolve this, use `chrome.runtime.getURL` (or replace chrome with browser for Firefox) to get the fully-qualified URL for a file in the extension.
3. `tabs.query` is not allowed in Firefox without the tabs permission in the `manifest.json` but it's allowed in Chrome if the tab matches the host permissions in `manifest.json`.
4. The `declarativeContent` API that Chrome has is not yet implemented in Firefox.

---

## Some Additional Differences

1. URLs in CSS files in Firefox are resolved relative to the CSS file, whereas in Chrome they're resolved relative to the current page.
2. Firefox does not allow functions like `alert`, `confirm` or `prompt` in background scripts.
3. Chrome allows passing relative URLs when making a request (for example, `/user`), however, Firefox requires absolute URLs.

---

## Packaging and Publishing Extensions Experience

When packaging the extension to publish it, in Chrome the `manifest.json` file should be in the root of the package. Whereas in Firefox the extension should be encapsulated in a directory that contains `manifest.json` at the root of it.

Here's an example of how a Chrome extension package structure would look like:

```
root
|
|
|_ _ _ manifest.json
```

And here's how it would look like in a Firefox extension package:

```
root
|
|
|_ _ _ my-extension
       |
       |
       |_ _ _ manifest.json
```

When it comes to publishing your extension, Google requires a one time fee of $25 (at the time of writing this) to create a developer account. Once you do, you don't need to make any additional payments when adding more extensions. With Firefox, you don't need to pay anything to publish an extension.

Once you have a developer account on both platforms, you can upload your extension.

When uploading your extension on Chrome, you will be asked to enter a lot of information regarding the name of the extension, description, a variety of images in different sizes, and other information that the user will see when downloading your extension. You will also be required to enter a few details regarding privacy and handling user data based on the permissions you're asking for in manifest.json. You also can enter a Google Analytics code that helps you track your extension and its users more thoroughly. Once you are done, the review process can take some time before your extension is published on the Chrome Webstore.

When uploading your extension on Firefox, you will be asked first to enter a few information regarding remote code execution, privacy and other security information as well. Then, you will get to enter almost the same information as for Chrome regarding the name, description, etc... However, Firefox requires less images and isn't as strict about the sizing as Chrome. Firefox does not allow adding a Google Analytics tracking code to track your extension. Once you're done, your extension will be published right away.

As for updating your extension, for Chrome you just need to upload the latest package, and if there are no changes in the permissions, you don't really need to enter any other information. If you have any changes in the permissions you might need to fill out more privacy and security related information. Once you're done, your extension will be reviewed and if it's approved it will be published.

For Firefox, when updating you will need to enter the same information as before regarding security and remote execution. You will also be asked to add  Changelog information for your users to know what changed. Once you're done, your extension will be published right away.