Progress Listeners


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.


Progress Listeners

Progress listeners allow extensions to be notified of events associated with documents loading in the browser and with tab switching events. Progress listeners implement the nsIWebProgressListener interface.

Note that if you just want to execute your code each time a page loads, you can use an an easier method, onPageLoad(). Note that onPageLoad does not fire for back button clicks.

In the examples below the progress listener is attached to the tabbrowser, which means you don't get any notifications for inactive tabs. Firefox 3.5 includes a way to set up a listener for all tabs, selected and not: Listening to events on all tabs.


  1. Create an object which implements nsIWebProgressListener:
    const STATE_START = Ci.nsIWebProgressListener.STATE_START;
    const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
    var myListener = {
        QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
        onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {
            // If you use myListener for more than one tab/window, use
            // aWebProgress.DOMWindow to obtain the tab/window which triggers the state change
            if (aFlag & STATE_START) {
                // This fires when the load event is initiated
            if (aFlag & STATE_STOP) {
                // This fires when the load finishes
        onLocationChange: function(aProgress, aRequest, aURI) {
            // This fires when the location bar changes; that is load event is confirmed
            // or when the user switches tabs. If you use myListener for more than one tab/window,
            // use aProgress.DOMWindow to obtain the tab/window which triggered the change.
        // For definitions of the remaining functions see related documentation
        onProgressChange: function(aWebProgress, aRequest, curSelf, maxSelf, curTot, maxTot) {},
        onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
        onSecurityChange: function(aWebProgress, aRequest, aState) {}
  2. Attach the progress listener to a <browser> or a <tabbrowser> element using AddProgressListener, for example for Firefox put the following code in a load listener of a main window:

    When used with a browser, the second argument is a mask which determines the type of events that will be received. Note that the browser uses a weak reference to your listener object, so make sure to keep an external reference to your object to ensure that it stays in memory.

    When used with a tabbrowser, you cannot choose which types of events that will be received. Instead, you receive those events that the tabbrowser is interested in, except that the onLinkIconAvailable and onRefreshAttempted notifications are optional. The tabbrowser uses a strong reference to your listener object.


Gecko 2.0 note


Starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), all events are optional. The tabbrowser only notifies you of the events for which you provide a callback.

Remember to change myListener to a unique identifier.

Example: Notification when the value in Address Bar changes

A commonly asked question is how to get notified whenever the URL in the address bar (also known as location bar) changes. Using the following code, you will get notified when user navigates to another page (by clicking a link, using the back/forward button, by typing an address in the Location Bar, etc.) and also when user switches tabs.

var myExtension = {
    oldURL: null,

    init: function() {

    uninit: function() {

    processNewURL: function(aURI) {
        if (aURI.spec == this.oldURL) return;

        // now we know the url is new...
        this.oldURL = aURI.spec;

    // nsIWebProgressListener
    QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",

    onLocationChange: function(aProgress, aRequest, aURI) {

    onStateChange: function() {},
    onProgressChange: function() {},
    onStatusChange: function() {},
    onSecurityChange: function() {}

window.addEventListener("load", function() { myExtension.init() }, false);
window.addEventListener("unload", function() { myExtension.uninit() }, false);

Note: If you use the same listener for more than one tab/window, use aWebProgress.DOMWindow in the callback methods to obtain the tab/window which triggers the state change or event.

Example: Example of listener for anchor change

The above example "Notification when the value in Address Bar changes" fires multiple times, one of which is when the tab is changed. In some cases you want to catch only a location change when the anchor changes. To do this the optional aFlags parameter of the onLocationChange listener is used.

var myExt_urlBarListener = {
    onLocationChange: function (aProgress, aRequest, aURI, aFlags) {
        if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
            //anchor clicked!
            var domWin = aProgress.DOMWindow;
            var domDoc = domWin.document;

You can learn about this here: nsIWebProgressListener - Location Change Flags