Cookie Opt-In: doing the GOD DAMN CORRECT THING


Have you been in the situation where you—and your customer!—want to do the right thing, and only load third-party cookies after an actual opt-in? Fond of the Cookie Consent widget like I am? Read on!

Cookie Consent is decent code to ask your visitors if you may place some of those dreadful carb-laden things on their computer. I recommend it for most websites.

Most customers prefer the ‘inform only’ option where you’re out of luck if you wish to deny cookies. But behold! I have a customer who wants to do the right thing! And only load third-party tracking cookies after an explicit ‘yes’. Cookie Consent even has a page dedicated to setting that up.


The example provided treats dismiss as allow and all those third-party cookies are dumped on all those poor devices! The horror!

Bad code, from the example

var type = this.options.type;
  var didConsent = this.hasConsented();
  if (type == 'opt-in' && didConsent) {
    // enable cookies

But to actually only act on allow, do this:

var type = this.options.type
if (type === 'opt-in' && status === 'allow') {

It’s a known issue, although it’s not clear if this will be fixed, or behaving as intended. (??!)

So….how do we pull off delayed third-party loading?

We use HTML <templates>! Supported by all browsers except legacy IE.

What it does, is put the third-party stuff into an inert block on the page. With a little scripting magic, you can bring it to life!

Here is the braindead version:

<template id="cookieConsent">
  <script type="text/javascript">
    (function() {
        var ga = document.createElement('script');
        // ... etc

And how to revive it:

var content = document.querySelector('#cookieConsent').content
var clone = document.importNode(content, true)

Totally works.

By the by

If you’re copying and pasting the provided snippet from Cookie Consent, you’re an idiot.

Pull in those resources so you have everything locally. And add them to your production bundle so everything comes down the wire with the absolute minimum amount of overhead.

Example for Rails:

$ curl -O
mv cookieconsent.min.js vendor/assets/javascripts
// in application.js:
//= require cookieconsent.min

$ curl -O
mv cookieconsent.min.css vendor/assets/stylesheets
// in application.scss:
@import "cookieconsent.min";

And put everything related to this in an IIFE, comme ca: