20

Firefox has launched a feature called Tracking protection in v42.0. It blocks several tracking scripts such as Google Analytics, Marketo, LinkedIn, etc.

Console output of the "Tracking protection" warnings

I was trying to detect it through navigator.DoNotTrack, but it returns unspecified in both cases – browsing in regular mode, and browsing in private mode – using Firefox 42.0 on Mac.

How can I detect in JavaScript whether a user is viewing the website with the Tracking protection on, since navigator.DoNotTrack fails?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • 1
    "how can I detect if a user is using tracking protection?" Seems to kind of miss the point of tracking protection, don't you think? – TylerH Jan 28 '16 at 19:34
  • 6
    @TylerH: Not if you want to tell the user something like "you're missing on important features of the app - use regular browsing mode and this and that will be available for you". – Petr Hejda Jan 28 '16 at 19:38
  • 1
    Yeah, avoiding such tracking messages is the *point* of tracking protection/private browsing. You do not want to be tracked, even indirectly. AKA I don't want you to know where I am, or even that I'm in your area. Just put one of those "this site uses cookies" type banners across the top of your page for all users. – TylerH May 05 '16 at 13:15

3 Answers3

20

navigator.donottrack only shows the setting of the "Do not track" preference. It does not tell if tracking protection, which is a different feature, is enabled. Tracking protection is enabled automatically when in private browsing mode, but users can change a setting in about:config to have it enabled full time.

While you can't tell directly if the feature is enabled, you can check for its effects with something like this:

var canreach = false;
$(function() {
    $('<img/>')
        .attr("src", "//apps.facebook.com/favicon.ico")
        .load(function(){canreach = true;})
        .css("display", "none")
        .appendTo(document.body);
});

Firefox uses a list obtained from Disconnect for its tracking protection; just use a domain that you know is on that list, and an image that you know will exist.

Of course, this could flag any number of causes for the image not to load, including network connectivity problems, ad blocking software, filtering proxies, etc.

miken32
  • 42,008
  • 16
  • 111
  • 154
8

Here is slightly improved version of miken32's answer using Deferred:

function whenNoTrackingProtection() {
    if (!whenNoTrackingProtection.promise) {
        var dfd = new $.Deferred();
        whenNoTrackingProtection.promise = dfd.promise();

        var time = Date.now();
        $('<img/>')
            .attr('src', '//apps.facebook.com/favicon.ico')
            .on('load', dfd.resolve)
            .on('error', function() {
                if ((Date.now() - time) < 50) {
                    dfd.reject();
                } else {
                    // The request took to long, it seems this is a network error.
                    dfd.resolve();
                }
            });
    }

    return whenNoTrackingProtection.promise;
}

or without jQuery, using Promise:

function whenNoTrackingProtection() {
    if (!whenNoTrackingProtection.promise) {
        whenNoTrackingProtection.promise = new Promise(function(resolve, reject) {
            var time = Date.now();
            var img = new Image();
            img.onload = resolve;
            img.onerror = function() {
                if ((Date.now() - time) < 50) {
                    reject();
                } else {
                    // The request took to long, it seems this is a network error.
                    resolve();
                }
            };
            img.src = '//apps.facebook.com/favicon.ico';
        });
    }

    return whenNoTrackingProtection.promise;
}
Graham P Heath
  • 7,009
  • 3
  • 31
  • 45
SleepWalker
  • 1,152
  • 14
  • 17
  • 2
    I like this code, but unfortunately for my usage `//apps.facebook.com/favicon.ico` no longer broke in privacy mode. I'm instead using a similar asset hosted on the service that is blocked by Privacy mode. – Graham P Heath Jun 13 '19 at 23:02
4

Here is an updated solution without using jQuery, using Promise. Thanks @miken32 and @sleepwalker.

Why do I preferer this solution instead of a navigator.doNotTrack based one? In Firefox, navigator.doNotTrack returns 1 on strict Enhanced Tracking Protection but in Google Chrome user needs to enable Send a "Do Not Track" request with your browsing traffic.

function whenNoTrackingProtection() {
    if (!whenNoTrackingProtection.promise) {
        whenNoTrackingProtection.promise = new Promise(function(resolve, reject) {
            var time = Date.now();
            var img = new Image();
            img.onload = resolve;
            img.onerror = function() {
                if ((Date.now() - time) < 50) {
                    reject(new Error("Rejected."));
                } else {
                    resolve(new Error("Takes too long."));
                }
            };
            img.src = '//www.facebook.com/tr/';
        }).then((result) => {
          console.log("Tracking OK");
        }).catch(e => {
          console.log("Tracking KAO");
          console.log(e)
        });
    }
}
whenNoTrackingProtection()
jrosell
  • 1,445
  • 14
  • 20