Supporting private browsing mode

  • Revision slug: Supporting_private_browsing_mode
  • Revision title: Supporting private browsing mode
  • Revision id: 103701
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment 5 words added, 19 words removed

Revision Content

{{ fx_minversion_header("3") }}

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 {{ interface("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 {{ interface("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.

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.

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 {
  background: #eee
}

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.

See also

 

Revision Source

<p>{{ fx_minversion_header("3") }}</p>
<p>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.</p>
<p>When private browsing mode is enabled, temporary, databases are created to be used for cookies and <a class="internal" href="/en/DOM/Storage#localStorage" title="en/DOM/Storage#localStorage">local storage</a>; 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.</p>
<p>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 {{ interface("nsIPrivateBrowsingService") }} interface.</p>
<h2>Detecting private browsing mode</h2>
<p>Determining whether or not the user is currently in private browsing mode is simple.  Just check the value of the <code>privateBrowsingEnabled</code> attribute on the {{ interface("nsIPrivateBrowsingService") }} service.</p>
<pre class="brush: js">var pbs = Components.classes["@mozilla.org/privatebrowsing;1"]
                    .getService(Components.interfaces.nsIPrivateBrowsingService);
var inPrivateBrowsingMode = pbs.privateBrowsingEnabled;

if (!inPrivateBrowsingMode) {
  /* save private information */
}</pre>
<p>In the above example, we only save the user's private information if not in private browsing mode.</p>
<div class="note"><strong>Note:</strong> 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.</div>
<h2>Turning private browsing on and off</h2>
<p>Extensions can turn private browsing mode on and off by manipulating the value of the <code>privateBrowsingEnabled</code> attribute.</p>
<pre class="brush: js">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;
</pre>
<p>In this example, we save the current state of the private browsing mode setting in the <code>oldPrivateMode</code> variable, then turn on private browsing by setting its value to <code>true</code>.  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 <a class="internal" href="/en/Places" title="En/Places">Places</a> database without affecting its contents.</p>
<h2>Private browsing notifications</h2>
<p>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 <code>browser:purge-session-history</code> 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.</p>
<h3>A private browser listener helper object</h3>
<p>This helper object registers listeners for private browsing mode changes.  This handles interacting with the private browsing service so you don't have to.</p>
<pre class="brush: js">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 &amp;&amp;
            "onEnterPrivateBrowsing" in this._watcher) {
          this.watcher.onEnterPrivateBrowsing();
        }
      } else if (aData == "exit") {
        this._inPrivateBrowsing = false;
        if (this.watcher &amp;&amp;
            "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;
  }
};
</pre>
<p>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.</p>
<h3>Using the helper</h3>
<p>The helper described above is very easy to use.  Simply instantiate the helper, then you can use its <code>inPrivateBrowsing</code> flag to detect whether or not private browsing is currently enabled, as shown here:</p>
<pre class="brush: js">var listener = new PrivateBrowsingListener();
 
if (listener.inPrivateBrowsing) {
  // we are in private browsing mode!
} else {
  // we are not in private browsing mode!
}
</pre>
<p>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.</p>
<pre class="brush: js">var listener = new PrivateBrowsingListener();
listener.watcher = {
  onEnterPrivateBrowsing : function() {
    // we have just entered private browsing mode!
  },
 
  onExitPrivateBrowsing : function() {
    // we have just left private browsing mode!
  }
};
</pre>
<h2>Canceling shutting off private browsing mode</h2>
<p>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 <code>private-browsing-cancel-vote</code> notification with the subject "exit", and set its <code>data</code> field to <code>true</code> to cancel the operation, like this:</p>
<pre class="brush: js">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);
</pre>
<div class="note"><strong>Note:</strong> 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.</div>
<h2>Private browsing for theme designers</h2>
<p>If you want to make your theme look different when used in private browsing mode, you can do so quite easily by using the <code>browsingmode</code> attribute in the <code>window</code> element in <code>browser.xul</code>.  This attribute has the value "normal" when the user isn't in private browsing mode, and is "private" when in private browsing mode.</p>
<p>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:</p>
<pre>[browsingmode=private] #urlbar {
  background: #eee
}
</pre>
<h2>Private browsing for plug-in authors</h2>
<p>Plug-ins can detect whether or not private browsing mode is in effect by using the <a class="internal" href="/en/NPN_GetValue" title="En/NPN GetValue"><code>NPN_GetValue()</code></a> function to check the current value of the <code>NPNVprivateModeBool</code> variable.  See <a class="internal" href="/En/Supporting_private_browsing_in_plugins" title="en/Supporting private browsing in plugins">Supporting private browsing in plugins</a> for details.</p>
<h2>See also</h2>
<ul> <li>{{ interface("nsIPrivateBrowsingService") }}</li> <li><code><a class="internal" href="/en/NPN_GetValue" title="En/NPN GetValue">NPN_GetValue()</a></code></li> <li><a class="external" href="http://ehsanakhgari.org/blog/2008-11-08/prepare-your-add-private-browsing" title="http://ehsanakhgari.org/blog/2008-11-08/prepare-your-add-private-browsing">Prepare your add-on for private browsing</a></li>
</ul>
<p> </p>
Revert to this revision