How to Track AdBlock Users in Google Analytics even they block JavaScript / Cookies


header image: Adblock Cookie Monster

Reading Time: 8min
(www.robert-matthees.de)

by Robert Matthees > E-commerce > GA Adblock (2017-08-06)

Why do AdBlockers kill your Google Analytics data?

Do you know that around 11% of the global internet population is blocking ads on the web (PageFair, 02/2017 )? AdBlockers are browser plugins that stop ads from being loaded on e-commerce projects, and most of them will kick out your Google Analytics Tracking too. In Germany, even 1 out of 5 desktop users will come with a running AdBlocker (Internet World, 06/2017 ). I realised the urgency of tackling this trend when I was looking at the Google Analytics E-commerce Report of a Webshop I was working on, and around 21% of the desktop conversions were missing in Google Analytics. My mind went: Quite exactly the percentage of adblocking visitors. Let's get them back! And there you go: Please enjoy the little Google Analytics Hack below. It even works for visitors that block JavaScript and Cookies in their browser settings entirely. What you will need is just a little bit of PHP and some additional lines in JavaScript (download example code ).


1st) Identify AdBlock Users with JavaScript Example Code

Detecting a visitor whose browser is blocking your Google Analytics Tracking from being loaded is quite simple. The best way is to check if the browser window knows the ga() function at all. And if not, well, something must have blocked Google Analytics from being loaded:

window.addEventListener('load', function() {
 if(window.ga && ga.create) {
    //Google Analytics is working
 } else {
   //Google Analytics is blocked
 }
}, false);

//To check Google Tag Manager, use: if(window.google_tag_manager)


2nd) Call Google Analytics Servers with PHP from Backend

With the script above, you can easily find out if the visitor on your website is blocking Google Analytics. But how can you track her anyway? You may have heard of the Google Analytics Measurement Protocol which allows developers to make HTTP requests to send raw user interaction data directly to Google Analytics servers. With just a few lines of code you can create a simple Backend API in PHP for Google Analytics Tracking (hidden from AdBlockers, that doesn't rely on JavaScript at all):

<?php
//Get some extra info about the user
$user_agent = $_SERVER['HTTP_USER_AGENT'];

//Test Data for GA Measurement Protocol
$data1 = array(
 'v' => 1,
 'tid' => 'UA-82381XXX-3', //Enter Yours
 'aip' => 1,
 'cid' => $cid, //we will create this in a bit
 'ua' => $user_agent,
 't' => 'pageview',
 'dh' => 'www.your-domain.de', //Enter Yours
 'dp' => '/ga-test/',
 'dt' => 'ga test'
);

//Send to GA Server
$url = 'https://www.google-analytics.com/collect';
$content1 = http_build_query($data1);
$content1 = utf8_encode($content1);
$ch1 = curl_init();
curl_setopt($ch1,CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch1, CURLOPT_URL, $url);
curl_setopt($ch1,CURLOPT_HTTPHEADER,array('Content-type: application/x-www-form-urlencoded'));
curl_setopt($ch1,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
curl_setopt($ch1,CURLOPT_POST, TRUE);
curl_setopt($ch1,CURLOPT_POSTFIELDS, $content1);
curl_setopt($ch1,CURLOPT_RETURNTRANSFER, TRUE);
curl_exec($ch1);
curl_close($ch1);
?>

If you detect an ad blocking user that kicked out your Google Analytics Tracking (for example with the JavaScript above), you can call your Google Analytics PHP API to record the hit anyway now. But there is one thing you have to keep in mind: The Google Analytics Tracking with Measurement Protocol doesn't work like the default Google Analytics auto mode that assigns Client IDs to your visitors automatically and stores them into cookies to identify them as returning visitors and on all stages of their journey. Using the Measurement Protocol, you have to do it manually. And Client IDs are really important to track a visitor's journey through your e-commerce project.


3rd) Assign & Handle Unique Client IDs even the Visitor is blocking JavaScript / Cookies

As we have to assign unique Client IDs to our visitors for proper tracking in Google Analytics, I use a little PHP Script that does five things:

Like this, you can store a unique Client ID in a PHP-Session-Variable even if a visitor is blocking Cookies. This enables you to identify the user at least during the entire session. (It won't recognise returning visitors because of the missing cookie. But it will track them as new ones.) If you don't store the Client ID for a visitor at all, a new one would be created on every page view. Like this, you couldn't track a user's journey at all as every new page view would seem to come from a different visitor in Google Analytics. That's why we try to set a long lasting Cookie. And just in case this isn't possible, we will have the Client ID at least stored in a PHP-Session-Variable (just in case of a Cookie blocking user). This is how my ga-cid.php looks like:

<?php
header("Cache-Control: no-cache, must-revalidate"); 
header("Pragma: no-cache");
session_start();

//no cookie, no session
if ((!isset($_COOKIE['cid'])) && (!isset($_SESSION['cid']))) {
 $_SESSION['cid'] = sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
   mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
   mt_rand( 0, 0xffff ),
   mt_rand( 0, 0x0fff ) | 0x4000,
   mt_rand( 0, 0x3fff ) | 0x8000,
   mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
 );
}

//cookie prior session
if (isset($_COOKIE['cid'])) {
 $_SESSION['cid'] = $_COOKIE['cid'];
}

//no cookie, but session
if ((!isset($_COOKIE['cid'])) && (isset($_SESSION['cid']))) {
 setcookie("cid", $_SESSION['cid'], time()+3600*24*365);
}

$cid = $_SESSION['cid']; 
if ($_GET['return']=="cid") { echo $cid; }
?>

I include this script in my little PHP Google Analytics API as you will see below in a second. Further, I use it to initialise Google Analytics Tracking in the Frontend with the correct Client ID. This is especially important for those users who just activated JavaScript in their browsers after they initially came to the website blocking it. This happens quite often — for example after you displayed a Please-activate-JS-message. If you would assign a new Client ID to these users once they activated JavaScript, all previous tracking data of the user journey (before they approved JS for the site) would be lost as it wouldn't be associated with the same session.


4th) Hit your Google Analytics Tracking API from Frontend (without / with JavaScript)

Now, you have a Backend Tracking via your Google Analytics API that works even without JavaScript. But how can you call this API without JavaScript from the Frontend? Probably, the best way to call the Google Analytics API in the case of blocked JavaScript is to use the Noscript-Tag. The Noscript-Tag contains HTML-Code which shows up if JavaScript is disabled. Normally, it contains an error message that tells the user to switch on JavaScript. Instead, we will put an Image-Tag inside the Noscript-Tag that contains our PHP-Tracking-API as image source attribute. The code itself will return a transparent Tracking Pixel and call the Google Analytics Measurement Protocol to record the hit:

<script src="ga-trackit.js"></script>
<noscript>JS disabled, use backend tracking.<br><img src="ga-trackit.php"></noscript>
<div id="test"></div>

The ga-trackit.js will initialise Google Analytics in the first step. Here, we tell the loader not to create a Google Analytics Cookie as we will work with our own Client IDs. These Client IDs come from our PHP-Script as described above. We will request them with little Ajax Calls. And just in case the Ajax Call doesn't work for some reason whatsoever, the script will tell Google Analytics to start in the default (auto) mode. And if something blocked Google Analytics from being loaded, it will inject our Backend Tracking Pixel into the DOM / HTML:

//ga init
(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');

//get Client ID and start Google Analytics
var xhr = new XMLHttpRequest();
xhr.open('GET', 'ga-cid.php?return=cid');
xhr.onload = function() {
 if (xhr.status === 200) { //get|create cid
   ga('create', 'UA-82381XXX-3', { //Enter Yours
     'storage': 'none',
     'clientId': xhr.responseText
   });
 } else { //or use ga auto
   ga('create', 'UA-82381XXX-3', 'auto'); //Enter Yours
 }
 ga('set', 'anonymizeIp', true); ga('send', 'pageview');
};
xhr.send();

//adblock handler
window.addEventListener('load', function() {
 if(window.ga && ga.create) { //all good, no AdBlocker
   document.getElementById("test").innerHTML = 'Google Analytics is working.';
 } else { //GA blocked, inject Tracking Pixel to call Backend API
   document.getElementById("test").innerHTML = 'Google Analytics is blocked, use backend tracking.<br><img src="ga-trackit.php">';
 }
}, false);

The full ga-trackit.php (with the ga-cid.php include plus the code that returns the Transparent Tracking Pixel) looks like this now:

<?php
//Get unique Client ID
require_once 'ga-cid.php';

//Return Transparent Pixel
header("Content-type: image/png");
$img = imagecreatetruecolor(1, 1);
imagesavealpha($img, true);
$color = imagecolorallocatealpha($img, 255, 255, 255, 127);
imagefill($img, 0, 0, $color);
imagepng($img);
imagedestroy($img);

//Get some extra info about the user
$user_agent = $_SERVER['HTTP_USER_AGENT'];

//Test Data for GA Measurement Protocol
$data1 = array(
 'v' => 1,
 'tid' => 'UA-82381XXX-3', //Enter Yours
 'aip' => 1,
 'cid' => $cid, //we will create this in a bit
 'ua' => $user_agent,
 't' => 'pageview',
 'dh' => 'www.your-domain.de', //Enter Yours
 'dp' => '/ga-test/',
 'dt' => 'ga test'
);

//Send to GA Server
$url = 'https://www.google-analytics.com/collect';
$content1 = http_build_query($data1);
$content1 = utf8_encode($content1);
$ch1 = curl_init();
curl_setopt($ch1,CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch1, CURLOPT_URL, $url);
curl_setopt($ch1,CURLOPT_HTTPHEADER,array('Content-type: application/x-www-form-urlencoded'));
curl_setopt($ch1,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
curl_setopt($ch1,CURLOPT_POST, TRUE);
curl_setopt($ch1,CURLOPT_POSTFIELDS, $content1);
curl_setopt($ch1,CURLOPT_RETURNTRANSFER, TRUE);
curl_exec($ch1);
curl_close($ch1);
?>

You can (and should) add more parameters to your tracking data, just check the Measurement Protocol Parameter List and you will find what you need for your insights — especially with regard to Ecommerce Tracking.


5th) Download AdBlock Google Analytics Tracking Example Code in JavaScript / PHP

Click here to download the AdBlock Google Analytics Tracking Example Code . You can test the tracking in the Real Time Report of Google Analytics. And as you may have realised, I am able to code, some say even quite well, but I am definitely not a developer (rather enjoy working on the business side of things). Which means, probably, you are able to make a more beautiful version of all this if you are working rather on the development side. Feel free to send through a cool version and I will upload it here with a link to your website or GitHub profile.


Final Notes about your No-Cookie / No-JavaScript / AbBlocker Tracking

I hope you have enjoyed my concept and you will make the best out of it!

Please share these ideas with your peers for further feedback & review on:


Impact of ePrivacy Regulation (EU)

If you have knowledge about the impact of the coming ePrivacy Regulation , please get in touch as I want to discuss this topic in detail. Because here, we set a First Party Cookie with data (maybe) processed by a Third Party (Google Inc.). On the other hand, the same Client ID can be used to store data like products in a saved shopping cart. The Factsheet about Stronger privacy rules for electronic communications (01/2017) provided by the European Commission states:

Users must be in control of any privacy-sensitive information stored on their devices, without having to click on a banner asking for their consent on cookies each time they visit a website. Browser settings will offer an easy way to allow or refuse cookies. The proposal clarifies that no consent is needed for non-privacy intrusive cookies improving internet experience (e.g. to remember shopping cart history). Cookies set by a visited website counting the number of visitors to that website will no longer require consent.

Please get in touch if you want to discuss this topic. It's quite on top of my agenda and I would be delighted to receive additional information and your opinion. Thanks for sharing this concept paper now on:


You may enjoy my GitHub Open Source (05/2017):

ga-rm.js Plugin for Interaction Tracking
in Google Analytics