How to properly check for Do Not Track with JavaScript

Photo of author

Rob Woodgate



Every modern browser has a “Do Not Track” setting (DNT), which tells websites whether the user wants to be tracked or not.

It’s been around since about 2011, but it’s been largely ignored until recently, because the definition of “tracking” has been hotly debated.

The advent of GDPR has rekindled the idea of DNT, because it it an easy and highly efficient way for users to convey consent (or not) to tracking.

So what is tracking?

Well, the W3C proposed specification defines it as:

the collection of data regarding a particular user’s activity across multiple distinct contexts and the retention, use, or sharing of data derived from that activity outside the context in which it occurred. A context is a set of resources that are controlled by the same party or jointly controlled by a set of parties.

Under this definition, collecting visitor analytics and conversion data for your own business purposes would not be “tracking”, but allowing that data to be used by other websites you don’t control for personalised advertising would.

This seems to dovetail nicely with interpretations of Article 21(2) of the GDPR, which hold that people have an absolute right to object to profiling for direct marketing.

Now, I’m no lawyer or fortune teller, but it looks like, going forward, DNT may well be increasingly used as a signal that the user doesn’t want to find themselves being segmented for personalised advertising and then endlessly retargeted for the thing they were looking at moments ago.

Anyhoo… that brings us to the subject of the post.

How To Properly Check DNT with Javascript

With the specification in flux, the implementation of DNT across browsers is pretty inconsistent, and most tutorials out there are wrong for some reason or another.

So, after spending a good few hours scouring the web and the specification, I decided to write a script to correctly handle:

  • The THREE primary states of DNT (0, 1, unset)
  • The possibility that the primary states have been EXTENDED
  • The various implementations of DNT to date (excluding Microsoft’s msTrackingProtectionEnabled() function, because this is superfluous and defunct)

So, without further ado, here’s my proposed DNT checking script:

// Get first defined value, starting with official property
var dnt = (typeof navigator.doNotTrack !== 'undefined')   ? navigator.doNotTrack
        : (typeof window.doNotTrack !== 'undefined')      ? window.doNotTrack
        : (typeof navigator.msDoNotTrack !== 'undefined') ? navigator.msDoNotTrack
        : null;
// The specification allows for strings BEGINNING with "0" or "1",
// possibly followed by DNT-extension characters, e.g. "1xyz"
// We can handle these strings, as well as integer 0/1's, using parseInt()
// We then just need to check for a 'yes' or 'no' from some older browsers
if (0 === parseInt(dnt) || 'no' == dnt) {
    // The user prefers to ALLOW TRACKING on this request
    // This is equivalent to the DNT: 0 request header
else if (1 === parseInt(dnt) || 'yes' == dnt) {
    // The user prefers NOT TO BE TRACKED on this request
    // This is equivalent to the DNT: 1 request header
else {
    // The user has NOT SPECIFIED a tracking preference on this request
    // This is equivalent to *NO* DNT request header

Hope this saves you a few hours!

Leave a Comment