Cookieless Google Analytics

Cookieless Google Analytics

So this is becoming really annoying : you have a website, you want to track users with Google Analytics... but you need to comply with GDPR.

What do you do ? You add a big cookie consent plugin which hurts your website performance, annoy your users and might be blocked by adblockers ? And even then, most people don't have accept tracking (who would?) unless you trick them into accepting it. What if there was a better solution ?

What we need to fix

Well there are two issues with Google Analytics :

  1. It sends the IP address, which is a personal information
  2. It uses a cookie to keep track of the user between pages

Anonymize IP address

This one is easy to fix and is even enabled by default in GA4.

gtag('config', '<GA_MEASUREMENT_ID>', { 'anonymize_ip': true })

or with

ga('set', 'anonymizeIp', true);

depending on if you use Universal Analytics or Google Tag Manager.

So this is more tricky because we need a unique id for each user. Obviously you can start a session for each user and use the session id as a reference. You can do this by using the following snippet when initializing Google Analytics:

ga('create', 'YOUR-GA-TRACKING-CODE', {
  'storage': 'none',
  'clientId': '<YOUR_USER_ID_HERE>'
});

But what if you are not using a session (eg: using cache) ? Then you have a problem. There are libs out there like fingerprintjs that helps to generate a unique token for a user, but again: do you really want to add one more library to your website ?

So here is what I'm using:

  • Generate a reasonably unique hash based on some unique values, including the IP address.
  • This last part is a bit tricky : either you have to provide it with php (again, no luck if you cache your webpages) or make a call to an external IP service (here, I'm using AWS)
  • And then, boom, you are good to go! The price to pay here is the extra http request to query the IP address on each page, but it's either that or not being able to cache your pages so probably this is worth the extra query.

Full solution available here as a gist