Supporting private browsing mode

This interface is deprecated since Firefox 20, and will probably be completely removed in Firefox 21.

See Supporting per-window private browsing for details.

Firefox 3.5 introduced private browsing mode, in which potentially private information is not recorded. This includes cookies, history information, download information, and so forth.

When private browsing mode is enabled, temporary, databases are created to be used for cookies and local storage; these databases are thrown away when private browsing mode is turned off, and the regular databases are re-activated. The temporary cookie and local storage databases start out empty.

Extensions that may record potentially private information may wish to hook into the private browsing service so that they can avoid saving personal information when private browsing mode is enabled.  Doing this is quite easy, using the nsIPrivateBrowsingService interface.

Detecting private browsing mode

Determining whether or not the user is currently in private browsing mode is simple.  Just check the value of the privateBrowsingEnabled attribute on the nsIPrivateBrowsingService service.

var pbs = Components.classes["@mozilla.org/privatebrowsing;1"]
                    .getService(Components.interfaces.nsIPrivateBrowsingService);
var inPrivateBrowsingMode = pbs.privateBrowsingEnabled;
if (!inPrivateBrowsingMode) {
  /* save private information */
}

In the above example, we only save the user's private information if not in private browsing mode.

Note: Private browsing mode may only be detected by chrome code, such as extensions; web content cannot detect whether or not private browsing is in effect.

Detecting whether private browsing mode is permanent

(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

Firefox 4 added support for having private browsing mode permanently enabled. The theme looks different in this scenario. To determine whether or not the browser is permanently in private browsing mode, you can look at the privatebrowsingmode attribute on the document root. Its value is "permanent" if private browsing is permanently enabled for the session, "temporary" if private browsing is temporarily enabled, or not defined at all if private browsing mode isn't active.

let docRoot = document.documentElement;
if (docRoot.hasAttribute("privatebrowsingmode")) {
  // Private browsing mode is enabled
}
if (docRoot.getAttribute("privatebrowsingmode") == "temporary") {
  // private browsing mode is temporary
}
if (docRoot.getAttribute("privatebrowsingmode") == "permanent") {
  // private browsing mode is permanent for this session
}

Turning private browsing on and off

Extensions can turn private browsing mode on and off by manipulating the value of the privateBrowsingEnabled attribute.

var pbs = Components.classes["@mozilla.org/privatebrowsing;1"]
                    .getService(Components.interfaces.nsIPrivateBrowsingService);
var oldPrivateMode = pbs.privateBrowsingMode;
pbs.privateBrowsingEnabled = true;
/* this is all private */
pbs.privateBrowsingEnabled = oldPrivateMode;

In this example, we save the current state of the private browsing mode setting in the oldPrivateMode variable, then turn on private browsing by setting its value to true.  From that point until we restore the original value of the private browsing mode setting, things are done privately.  This allows us to, for example, work with the Places database without affecting its contents.

Private browsing notifications

There are notifications available that allow you to easily watch for changes to the status of the private browsing mode, including detecting when it turns on and off.  In addition, there is a browser:purge-session-history notification that is sent when the browser purges private data that extensions can watch in order to know when it's time to do the same.

A private browser listener helper object

This helper object registers listeners for private browsing mode changes.  This handles interacting with the private browsing service so you don't have to.

function PrivateBrowsingListener() {
  this.init();
}
PrivateBrowsingListener.prototype = {
  _os: null,
  _inPrivateBrowsing: false, // whether we are in private browsing mode
  _watcher: null, // the watcher object
  init : function () {
    this._inited = true;
    this._os = Components.classes["@mozilla.org/observer-service;1"]
                         .getService(Components.interfaces.nsIObserverService);
    this._os.addObserver(this, "private-browsing", false);
    this._os.addObserver(this, "quit-application", false);
    try {
      var pbs = Components.classes["@mozilla.org/privatebrowsing;1"]
                          .getService(Components.interfaces.nsIPrivateBrowsingService);
      this._inPrivateBrowsing = pbs.privateBrowsingEnabled;
    } catch(ex) {
      // ignore exceptions in older versions of Firefox
    }
  },
  observe : function (aSubject, aTopic, aData) {
    if (aTopic == "private-browsing") {
      if (aData == "enter") {
        this._inPrivateBrowsing = true;
        if (this.watcher &&
            "onEnterPrivateBrowsing" in this._watcher) {
          this.watcher.onEnterPrivateBrowsing();
        }
      } else if (aData == "exit") {
        this._inPrivateBrowsing = false;
        if (this.watcher &&
            "onExitPrivateBrowsing" in this._watcher) {
          this.watcher.onExitPrivateBrowsing();
        }
      }
    } else if (aTopic == "quit-application") {
      this._os.removeObserver(this, "quit-application");
      this._os.removeObserver(this, "private-browsing");
    }
  },
  get inPrivateBrowsing() {
    return this._inPrivateBrowsing;
  },
  get watcher() {
    return this._watcher;
  },
  set watcher(val) {
    this._watcher = val;
  }
};

Of special note is the fact that this helper object is designed to not break on versions of Firefox without private browsing support (those prior to Firefox 3.5).  It will simply always report that private browsing is off, and will never call any registered watcher functions.

Using the helper

The helper described above is very easy to use.  Simply instantiate the helper, then you can use its inPrivateBrowsing flag to detect whether or not private browsing is currently enabled, as shown here:

var listener = new PrivateBrowsingListener();
if (listener.inPrivateBrowsing) {
  // we are in private browsing mode!
} else {
  // we are not in private browsing mode!
}

In addition, you can install watcher functions to be called when private browsing turns on and off, as shown in the following example.  This lets you passively monitor for changes in private browsing status.

var listener = new PrivateBrowsingListener();
listener.watcher = {
  onEnterPrivateBrowsing : function() {
    // we have just entered private browsing mode!
  },
  onExitPrivateBrowsing : function() {
    // we have just left private browsing mode!
  }
};

Canceling shutting off private browsing mode

Extensions can prevent private browsing mode from being shut off.  An extension might wish to do this if it's currently in the middle of an operation that prevents safely turning off private browsing (such as a database update operation, for example).  To do this, simply watch for the private browsing private-browsing-cancel-vote notification with the subject "exit", and set its data field to true to cancel the operation, like this:

var os = Components.classes["@mozilla.org/observer-service;1"]
                   .getService(Components.interfaces.nsIObserverService);
os.addObserver(function (aSubject, aTopic, aData) {
    aSubject.QueryInterface(Components.interfaces.nsISupportsPRBool);
    // if another extension has not already canceled entering the private mode
    if (!aSubject.data) {
      if (aData == "exit") { // if we are leaving the private mode
        /* you should display some user interface here */
        aSubject.data = true; // cancel the operation
      }
   }
}, "private-browsing-cancel-vote", false);
Note: A well-mannered extension should display some sort of user interface to indicate that private browsing mode will be kept on, and possibly offer the option to cancel whatever operation is preventing the extension from allowing private browsing to be shut off.

Other considerations for extensions

In some extensions, it's hard to decide whether the data retained by the extension should be written to disk in private browsing mode or not.  In such a case, it is considered good practice for the extension to enable respecting the private browsing mode based on a preference specific to that extension, and set that preference to true by default.  For example, the Fire.fm extension has a preference called "Disable station history and Scrobble when Firefox is in Private Mode", and disabling publishing of that information inside the private browsing mode by default.  It provides a means of disabling this behavior for users who do not want the extension to stop publishing the information in private browsing mode.

Note: It is not acceptable for an extension that records things like URLs or domains visited to even offer the option to opt out of private browsing mode.

Private browsing for theme designers

If you want to make your theme look different when used in private browsing mode, you can do so quite easily by using the browsingmode attribute in the window element in browser.xul.  This attribute has the value "normal" when the user isn't in private browsing mode, and is "private" when in private browsing mode.

For example, if you want to use a different background color for the URL bar when in private browsing mode, you could do the following:

[browsingmode=private] #urlbar {
  -moz-appearance: none;
  background: #eee
}

Similarly, if you want to theme the Firefox button in Firefox 4 differently when private browsing mode is permanent:

#main-window[privatebrowsingmode=temporary] #appmenu-button:not(:-moz-window-inactive) {
  -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
  -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
  -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
}

This snippet is pulled directly from the standard skin; you can customize as you see fit.

Private browsing for plug-in authors

Plug-ins can detect whether or not private browsing mode is in effect by using the NPN_GetValue() function to check the current value of the NPNVprivateModeBool variable.  See Supporting private browsing in plugins for details.

AMO policy and private browsing

In order to publicly list an add-on on addons.mozilla.org, the add-on must properly respect private browsing mode by not recording sensitive data while private browsing mode is active. This is a new policy that is just being implemented (as of February, 2010).

Note: During the transition period as this policy is put into effect, there is some leeway as well as a grace period. See this blog post by Ehsan Akhgari for details on the transition period.

The following categories define what's considered "sensitive" data:

  • The URLs of pages the user has visited.
  • The domains of sites the user has visited.
  • The content of pages the user has visited.
  • All data related to pages the user has visited, including cookies and form data.
  • Data used to customize the Firefox user interface based on what happens in private browsing mode.

Add-ons that don't properly respect private browsing mode will be rejected.

See also

Document Tags and Contributors

 Contributors to this page: teoli, ignisvulpis, Sheppy, Ehsan, Dao
 Last updated by: ignisvulpis,