Support for extensions using XUL/XPCOM or the Add-on SDK was removed in Firefox 57, released November 2017. As there is no supported version of Firefox enabling these technologies, this page will be removed by December 2020.

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

Starting from Firefox 53, no new legacy add-ons will be accepted on (AMO) for desktop Firefox and Firefox for Android.

Starting from Firefox 57, only extensions developed using WebExtensions APIs will be supported on Desktop Firefox and Firefox for Android.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to use WebExtensions APIs if they can. See the "Compatibility Milestones" document for more information.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.



Check whether a given object is private, so an add-on can respect private browsing


Per-window private browsing

Private browsing status is a property of an individual browser window.

The user enters private browsing by opening a new private browser window. When they do this, any existing non-private windows are kept open, so the user will typically have both private and non-private windows open at the same time.

Opting into private browsing

Add-ons built using the SDK must opt into private browsing by setting the following key in their package.json file:

"permissions": {"private-browsing": true}

If an add-on has not opted in, then the high-level SDK modules will not expose private windows, or objects (such as tabs) that are associated with private windows:

  • the windows module will not list any private browser windows, generate any events for private browser windows, or let the add-on open any private browser windows

  • the tabs module will not list any tabs that belong to private browser windows, and the add-on won't receive any events for such tabs

  • any ui components will not be displayed in private browser windows

  • any menus or menu items created using the context-menu will not be shown in context menus that belong to private browser windows

  • the page-mod module will not attach content scripts to documents belonging to private browser windows

  • any panel objects will not be shown if the active window is a private browser window

  • the selection module will not include any selections made in private browser windows

Add-ons that have opted in will see private windows, so they will need to use the private-browsing module to check whether objects are private, so as to avoid storing data derived from such objects.

Additionally, add-ons that use low-level modules such as window/utils may see private browser windows with certain functions, even if they have not explicitly opted into private browsing.

Respecting private browsing

The private-browsing module exports a single function isPrivate() that takes an object, which may be a BrowserWindow, tab, or worker, as an argument. It returns true only if the object is:

  • a private window, or
  • a tab belonging to a private window, or
  • a worker that's associated with a document hosted in a private window
  • any window, tab, or worker if the browser has been configured to never remember history (Options->Privacy->History)

Add-ons can use this API to decide whether or not to store user data. For example, here's an add-on that stores the titles of tabs the user loads, and uses isPrivate() to exclude the titles of tabs that were loaded into private windows:

var simpleStorage = require("simple-storage");

if (! = [];

require("tabs").on("ready", function(tab) {
  if (!require("sdk/private-browsing").isPrivate(tab)) {
  else {
    console.log("not storing, private data");

Here's an add-on that uses a page-mod to log the content of pages loaded by the user, unless the page is private. In the handler for the page-mod's attach event, it passes the worker into isPrivate():

var pageMod = require("sdk/page-mod");
var privateBrowsing = require("sdk/private-browsing");

var loggingScript = "self.port.on('log-content', function() {" +
                    "  console.log(document.body.innerHTML);" +

function logPublicPageContent(worker) {
  if (privateBrowsing.isPrivate(worker)) {
    console.log("private window, doing nothing");
  else {

  include: "*",
  contentScript: loggingScript,
  onAttach: logPublicPageContent

Tracking private-browsing exit

Sometimes it can be useful to cache some data from private windows while they are open, as long as you don't store it after the private browsing windows have been closed. For example, the "Downloads" window might want to display all downloads while there are still some private windows open, then clean out all the private data when all private windows have closed.

To do this with the SDK, you can listen to the system event named "last-pb-context-exited":

var events = require("sdk/system/events");

function listener(event) {
  console.log("last private window closed");

events.on("last-pb-context-exited", listener);




Function to check whether the given object is private. It takes an object as an argument, and returns true only if the object is:

  • a private BrowserWindow or
  • a tab belonging to a private window, or
  • a worker that's associated with a document hosted in a private window

object : any
The object to check. This may be a BrowserWindow, tab, or worker.