A pure JavaScript cookie-consent-banner for Google Analytics


Disclaimer: I am not a lawyer. This is not legal advice.

Disclaimer: I am also not a JavaScript developer. So don’t take this as JavaScript programming advice. :)

I like to know how many people visit my website, and what articles they are reading. Why? Because I find it can be quite motivating to see these numbers go up.

Because I am located in Germany, I need to provide a way for my site visitors to explicitly give their consent. Since the advent of GDPR and the European Cookie Law, there are many, many companies that offer services to help website owner with this. But I am software developer. I am not going to pay a monthly fee for a simple JavaScript pop-up! (Yes, yes, I know, these companies provide more than that. I am just trying to be funny here.)

However, I am not a JavaScript-developer, so I obviously didn’t try to write something from scratch. My requirements seemed simple enough: A nice little self-contained JavaScript solution without external dependencies. I was surprised how long it took me to find something like that. In the end, I use this gist as a starting point and made some changes.

Usage

You should customize these settings:

  • set privacy_policy_url to the URL of your privacy policy
  • set cookieDuration to the number of days you want the banner to re-appear after
  • search for UA-you-analytics-id-goes-here and replace it with your Google Analytics ID

Note that the HTML is using some Bootstrap 3 classes (row, col-...), which you might want to replace.

The code

My apologies for not cleaning this up more before posting it here. I already spent a lot of time getting it work, so I thought I would rather publish it in this desolate state, instead of not publishing it at all.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Based on https://gist.github.com/rosell-dk/217e1cfdf09bf01bb19f56644be0c6f7

var CookieBanner = (function() {
    return {
        'cookieDuration': 90,                           // Number of days before the cookie expires, and the banner reappears
        'cookieName': 'cookieConsent',                  // Name of our cookie
        'cookieAcceptedValue': 'analytics_accepted',    // Value of cookie if user accepts
        'cookieDeniedValue': 'analytics_denied',
        'privacy_policy_url': '/privacy-policy/',       // Link to your privacy policy
        'consentCallBack': (function () {               // Is called on every page-load if user accepts cookies
            console.error("You must assign a call back function to CookieBanner.consentCallBack")
        }),
        '_createDiv': function(html) {
            var bodytag = document.getElementsByTagName('body')[0];
            var div = document.createElement('div');
            div.setAttribute('id','cookie-law');
            div.innerHTML = html;

            bodytag.insertBefore(div,bodytag.firstChild); // Adds the Cookie Law Banner just after the opening <body> tag

            document.getElementsByTagName('body')[0].className+='cookiebanner'; //Adds a class to the <body> tag when the banner is visible

        },

        '_createCookie': function(name, value, days) {
            var expires;
            if (days) {
                var date = new Date();
                date.setTime(date.getTime()+(days*24*60*60*1000));
                expires = "; expires="+date.toGMTString();
            }
            else {
                expires = "";
            }
            document.cookie = name+"="+value+expires+"; path=/";
        },

        '_cookieExists': function(name) {
            return document.cookie.indexOf(name + "=") !== -1;
        },

        '_triggerCallBackIfUserAccepted': function () {
            if (CookieBanner.hasUserAccepted()) {
                CookieBanner.consentCallBack()
            }
        },

        'hasUserAccepted': function() {
            return document.cookie.indexOf(CookieBanner.cookieAcceptedValue) !== -1;
        },

        '_eraseCookie': function(name) {
            CookieBanner._createCookie(name,"",-1);
        },

        'createAcceptCookie': function() {
            CookieBanner._createCookie(CookieBanner.cookieName, CookieBanner.cookieAcceptedValue, CookieBanner.cookieDuration);
        },

        'createDenyCookie': function() {
            CookieBanner._createCookie(CookieBanner.cookieName, CookieBanner.cookieDeniedValue, CookieBanner.cookieDuration);
        },

        'closeBanner': function() {
            var element = document.getElementById('cookie-law');
            element.parentNode.removeChild(element);
        },

        'accept': function() {
            CookieBanner.createAcceptCookie();
            CookieBanner.closeBanner();
            CookieBanner._triggerCallBackIfUserAccepted()
        },

        'deny': function() {
            CookieBanner.createDenyCookie();
            CookieBanner.closeBanner();
        },

        'showIfCookieMissing': function(html) {
            if(CookieBanner._cookieExists(CookieBanner.cookieName) === false){
                CookieBanner._createDiv(html);
            }
            CookieBanner._triggerCallBackIfUserAccepted()
        }
    }

})();

window.onload = function(){
    var html = '<div class="row">' +
        '<div class="col-lg-9">' +
        'I would like to use Google Analytics to know how many people visit my site. <b>If you agree, your IP address will be anonymized.</b> ' +
        'You can read the legal details in my site\'s ' +
        '<a href="' + CookieBanner.privacy_policy_url + '">Privacy Policy</a>. ' +
        'By clicking "Accept", you agree to my use of cookies for the purpose of analytics.' +
        '</div>'

    html += '<div class="col-lg-3">'
    html += '<div class="btn btn-lg btn-block btn-primary" id="btn_accept" onclick="CookieBanner.accept();"><span>Accept</span></div>';
    html += '<div class="btn btn-lg btn-block btn-default" id="btn_deny" onclick="CookieBanner.deny();"><span>Deny</span></div>';
    html += '</div></div>' // col-lg-3, row
    CookieBanner.consentCallBack = (function () {
        // Google Analytics
        console.log("Loading Google Analytics, because you have accepted it's use.");
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
            (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

        ga('create', 'UA-you-analytics-id-goes-here', 'auto');
        ga('set', 'anonymizeIp', true);
        ga('send', 'pageview');

    })
    CookieBanner.showIfCookieMissing(html);
}

And here is the css, that you need to include yourself:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#cookie-law {
    display: flex;
    align-items: center;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 20px 5%;
    background-color: #ccc;
    z-index: 999;
}

#cookie-law > div > div {
    margin: 2em;
}

See also