Do Not Track (DNT) tutorial for Django

2013-03-24 00:00:00 +0000


Do Not Track (DNT) HTTP header is already supported by many browsers, but it was not really clear what it is supposed to do apart from expressing user’s preference not to be tracked. I think it may help to demonstrate this on an example. First of all DNT is not part of any standard. It was specified in Internet Draft (draft-mayer-do-not-track-00) that expired in 2011. Nonetheless, during hot discussions on EU cookie law), its supporters routinely use DNT as an example on “how it should be done properly”. So I’ve decided to give it a try on my website WebCookies.org.

Probably the most important thing to understand is that DNT header is not expected to do anything more than providing a way to tell the server that the user has light form of phobia related to web tracking prefers not to be tracked. What it actually means “to be tracked” is fully up to the webmaster. There are no “standard” tracking methods that should be disabled when DNT is on, there are no best practices or established consensus.

My website doesn’t sell anything and has no sophisticated behavioral profiling features that could satisfy the definition of “tracking”. But it uses Google Analytics, plus “like” buttons for two major social networks — Facebook and Google+. All of them could be treated as some kind of tracking, so I’ve decided that my website’s reaction to user’s DNT sign is to disable these features. And I’m using Django web framework for Python.

Using request objects

The simplest way to handle DNT just uses standard Django features and has no additional dependencies:

  1. Find out if user sets DNT by looking at headers in HTTP request.
  2. If yes, disable some parts of HTML template containing the "tracking" code. </ol> The first part can be done by looking at request.META in Django view, as in this example: def index(request): if 'HTTP_DNT' in request.META: dnt = True else: dnt = False return render_to_response('index.html', { 'dnt' : dnt } ) These are absolute basics of using Django views. Then we can use this dnt variable in relevant HTML template: And that's all — from now on your website will not send the statistics gathering code to people with DNT enabled. These HTML comments will actually appear in the page's HTML code, so you can see if it works.

    Using middleware

    There's another way to achieve the same goal, which is better suited for large sites, where code maintenance overhead is more important. In such case you can install django-security module (django-security on GitHub), which as of version 0.1.15b has pretty complete DNT support implemented as Django middleware. In such case you would do the following:
    1. Add security.middleware.DoNotTrackMiddleware to your application's middleware in settings.py: MIDDLEWARE_CLASSES = ( ... 'security.middleware.DoNotTrackMiddleware', ... ) This middleware will give you more clues about user preferences by setting request.dnt variable. It can take three values: True – user explicitly does not want tracking, False – user explicilty allows tracking, None – no DNT was sent, so user has no preference or uses browser with no DNT support, which means it's up to you to decide track or not to track. See relevant section in the Draft for detailed discussion of these options.
    2. Make sure template context processors contain django.core.context_processors.request: TEMPLATE_CONTEXT_PROCESSORS = ( ... 'django.core.context_processors.request', ... )
    3. In your views, call render_to_response with RequestContext so that templates will actually have access to request object: def index(request): return render_to_response('index.html', context_instance=RequestContext(request) )
    4. Now you can reference request.dnt in HTML templates to switch tracking blocks on and off: </ol>