New WebExtensions Guides and How-tos on MDN


The official launch of WebExtensions is happening in Firefox 48, but much of what you need is already supported in Firefox and AMO ( The best place to get started with WebExtensions is MDN, where you can find a trove of helpful information. I’d like to highlight a couple of recent additions that you might find useful:

Thank you to Will Bamberg for doing the bulk of this work. Remember that MDN is a community wiki, so anyone can help!

Writing an opt-in UI for an extension

Our review policies for (AMO) require transparency when it comes to an add-on’s features and how they might affect a user’s privacy and security.

These policies are particularly relevant in cases where an add-on includes monetization features that are unrelated to its main function. For example, a video downloader add-on could include a shopping recommendation feature that injects offers from commercial websites. In cases like this, to be listed on AMO the feature would need to be opt-in. Opt-in means the add-on needs to present to the user the option to enable the feature, with a default action of keeping it disabled.

We’re often asked for examples of add-ons that do this, so I decided to create a sample WebExtension for this purpose. You can find the code on GitHub, and the built and signed example can be downloaded here.

The extension implements two opt-in prompts:

  1. A new tab. Tab opt-in
  2. A panel in the main add-on button. Panel opt-in

(If you don’t recognize the dark theme in the screenshots, it’s because I’m using Firefox Developer Edition—currently Firefox 49—for testing.)

An add-on would normally implement one prompt or the other. Opening a new tab has the advantage of getting the user’s attention right away, and has more room for content. The main disadvantage is that it can annoy users and feel too pushy. The pop-up approach is more user-friendly because it appears when the user is ready to engage with the add-on and is better integrated with the add-on UI. However, it wouldn’t work if the add-on doesn’t include buttons.

This example is completely minimal, hence the almost complete lack of styling. However, it includes the elements that AMO policies deem necessary:

  • Text explaining clearly to the user what the opt-in feature does and why it’s being offered. In this case, the extra feature is a variation of the borderify example on GitHub.
  • A link to a privacy policy and/or more information about the feature. That page should spell out its privacy and security implications.
  • A clear choice between enabling the feature and keeping it disabled, defaulting to disabled. I set autofocus="true" to the Cancel button, which can be clearly seen in the popup screenshot.

Hitting the Return key in either case, or closing the opt-in tab should be assumed to mean that the user is choosing not to accept the feature (the tab closing case isn’t implemented in this example to make it easier to test). The example uses the storage API to keep track of two flags: one that indicates the user has clicked on either button, and one that indicates if the user has enabled the feature or not. After the opt-in is registered as shown, the tab won’t show up again, and the content changes to something else.

Note: I couldn’t find a way to look at the extension’s storage in the developer tools (I suppose it’s not implemented yet). You can clear the storage to reset the state of the extension by deleting the browser-extension-data folder in the profile.

Remember that sneaking in unwanted features is bad for your users and your add-on’s reputation, so make sure you give your users control and give them clear information to make a decision. Happy coding!

Using Google Analytics in Extensions

As an add-on developer, you may want to have usage reporting integrated into your add-on. This allows you to understand how your users are using the add-on in real life, which can often lead to important insights and code updates that improve user experience.

The most popular way to do this is to inject the Google Analytics script into your codebase as if it were a web page. However, this is incompatible with our review policies. Injecting remote scripts into privileged code – or even content – is very dangerous and it’s not allowed. Fortunately, there are ways to send reports to Google Analytics without resorting to remote script injection, and they are very easy to implement.

I created a branch of one of my add-ons to serve as a demo. The add-on is a WebExtension that injects a content script into some AMO pages to add links that are useful to admins and reviewers. The diff for the branch shouldn’t take much time to read and understand. It mostly comes down to this XHR:

let request = new XMLHttpRequest();
let message =
  "v=1&tid=" + GA_TRACKING_ID + "&cid= " + GA_CLIENT_ID + "&aip=1" +
  "&ds=add-on&t=event&ec=AAA&ea=" + aType;"POST", "", true);

In my demo I do everything from the content script code. For add-ons with a more complex structure, you should set up a background script that does the reporting and have content scripts send messages to it if needed.

I set up my reporting so the hits are sent as events. You can read about reporting types and all the different parameters in the Google Analytics developer docs.

Thanks to the real-time tracking feature I could see that my implementation was working right away:


That’s it! With just a few lines of code you can set up Google Analytics for your add-on safely, in a way that meets our review guidelines.