Measuring the impact of an ad blocker with GTM server-side

For many, one of the most important rationales for server-side Google Tag Manager seems to be its flexibility Ads and content blocker. After all, by virtue of the JavaScript container service from your domainYou are escaping from the many experimental devices that blocking technologies are using today.

Well, I’ve signed up over and over again to say how it’s done weak justification For server-side GTM use. By circumventing a file he wishes To block scripts, you are disrespecting them and forcing their browser to download scripts that they want to avoid downloading in the first place.

However, this is not another article lamenting this disconnect between data-hungry analysts and unsuspecting site visitors.

Instead, I want to take the technology that allows you to rip off Instead use it reveal.

While ad and content blockers should be allowed to run their course, I think it is absolutely necessary to measure their impact. This way you can count the number of your analytics and ad requests that have been blocked by these tools.

You can even use detection technology to conditionally block server-side tags! This way you can really act according to the user’s wishes And Keep this data flows between the browser and the server container alive.

By the way, if you are interested in learning more about ad blockers and content in general, I recommend listening to the Art Marketing Handbook podcast episode, where I interviewed Snyder’s house from Brave on this very topic.


Simmer . Newsletter

Subscribe to the Simmer newsletter to get the latest news and content from Simo Ahava right in your inbox!

blocker effect measurement

Let’s start with a major warning (the first of many):

This is the proof of concept. What I’m showing you here are some of the components you need to create a detection system, but most of the work has to be done on the client side (where the detection happens), so you need to modify these ideas to make sense of what or what is yours Works on the site.

In this article, I’ll show you how I measure three different things:

  • Homepage views percentage where advertisements been banned.
  • Homepage views percentage where Google Analytics It was forbidden.
  • Homepage views percentage where Google Tag Manager It was forbidden.

There are additional caveats regarding each of these measurements, but I’ll address them as they arise.

Note that to understand everything that is happening here, you need to have a fairly good understanding Server-side labeling. If you haven’t set it up yet, I recommend you take a look at my article on this topic.

custom customer form

I’m using a custom client form in the server container to capture requests for the ad blocker bait file In addition to the pixel used to create the event data object.

Ad blocker client

The bait file contains instructions for the browser to create an item with ID GxsCRdhiJi. This is the item you need to look for to find out if the file is blocked or not.

Client side script

Most of the magic has to be done on the client side.

On my site’s page template, I run the following script in an HTML page. Yes, you need to do it outside of Google Tag Manager, because if GTM is blocked, you won’t be able to measure the effect because the client side script is also blocked.

  // Set these to the endpoints configured in the Client template
  var baitPath = '';
  var pixelPath = '';
  // Prevent the script from running outside the home page
  if (document.location.pathname !== '/') return;
  // Inject the bait file
  var el = document.createElement('script');
  el.src = baitPath;
  var gaBlocked = false;
  // Run the detections at page load to avoid race conditions
  window.addEventListener('load', function() 
    // Send a HEAD request for the Universal Analytics library to see if it's blocked
    fetch('', method: 'HEAD', mode: 'no-cors')
        // If the load failed, assume GA was blocked
        gaBlocked = true;
        // Build the GA4 parameters, add additional parameters at your leisure
        var params = 
          ads_blocked: !document.querySelector('#GxsCRdhiJi'), // Detect if the bait file was blocked
          gtm_blocked: !(window.google_tag_manager && window.google_tag_manager.dataLayer), // Detect if gtm.js was blocked
          ga_blocked: gaBlocked // Detect if analytics.js was blocked
        // Build the pixel request with a unique, random Client ID
        var cid = Math.floor((Math.random() * 1000000) + 1) + '_' + new Date().getTime();
        var img = document.createElement('img'); = 'width: 1; height: 1; display: none;';
        img.src = pixelPath + '?client_id=' + cid + '&' + Object.keys(params).reduce(function(acc, cur)  return acc.concat(cur + '=' + params[cur]);, []).join('&');

I just want this script to run on the homepage, and because I’m too lazy to edit my templates, I simply exit the function if the current page’s path is not the site root.

NS baitPath And pixelPath, configure the corresponding settings you added to the customer form. The default values ​​are /ads-min.js for the bait file path, and /4dchk for the pixel path.

In the following chapters, I will tell you how I measure the use of ad blockers, Google Analytics blocking, and Google Tag Manager blocking.

Measure ad blockers

to measure the effect Ad blockers, I am using an old heuristic system to detect if the browser is blocking ads.

The browser sends a request to the server container, where the client form picks it up. The request must be for a file that is commonly blocked by ad blockers, such as ads-min.js.

var baitPath = '';
var el = document.createElement('script');
el.src = baitPath;

ads-min.js is prohibited

The purpose of the file is to create a dummy HTML element on the page with a specific identifier (GxsCRdhiJi If you are using the default form). If the item is not present when queried, it means that the download failed for one reason or another, one of them may be due to ad blockers.

legal notice: We don’t know why the download failed. It could be due to the ad blocker, but it could also be due to a network error or something else. So there is always some uncertainty in this regard.

Also note that filter lists such as, used in Mozilla Firefox and Microsoft Edge, match the domain name, making them very difficult to detect using a custom solution.

Measurement of GA . blockers

To measure whether Google Analytics is blocked or not, I use a very simple method. I manage fetch() Call the Universal Analytics JavaScript library. If this request fails, I will revert to block GA.

The request is sent using the HEAD method to prevent the browser’s resources from being used, and is sent with a file no-cors Mode to avoid CORS issues.

Here’s what the request looks like:

fetch('', method: 'HEAD', mode: 'no-cors')
  .catch(() => 
    // GA is blocked

legal notice: Again, we don’t know if it’s a blocker that prevents GA loading. Also, in Firefox, even in private Windows, Google Analytics is allowed to load, but its main methods are Bright to prevent it from working. This particular approach will not be able to detect this type of blocking.

GTM blocker measurement

For GTM, we take even in simpler approach. At the time of loading the window, we will check if the file window.google_tag_manager The interface is created and it also contains a nested object window.google_tag_manager.dataLayer.

gtm_blocked: !(window.google_tag_manager && window.google_tag_manager.dataLayer)

legal notice: All of the above warnings apply again. And it is important to remember that for example in Firefox, global window.google_tag_manager user interface He is Created, but since then dataLayer.push Brilliant, the GTM itself will not work.

Send pixel request to server container

Once you have your Booleans to see if these three vectors are blocked or not, it’s time to put everything together.

window.addEventListener('load', function() 
  fetch('', method: 'HEAD', mode: 'no-cors')
      gaBlocked = true;
      var params = 
        ads_blocked: !document.querySelector('#GxsCRdhiJi'),
        gtm_blocked: !(window.google_tag_manager && window.google_tag_manager.dataLayer),
        ga_blocked: gaBlocked
      var cid = Math.floor((Math.random() * 1000000) + 1) + '_' + new Date().getTime();
      var img = document.createElement('img'); = 'width: 1; height: 1; display: none;';
      img.src = pixelPath + '?client_id=' + cid + '&' + Object.keys(params).reduce(function(acc, cur)  return acc.concat(cur + '=' + params[cur]);, []).join('&');

The pixel request is waiting for the window to load completely And for Google Analytics fetch() request to complete. This way you won’t spoil any potential asynchronous race conditions.

In the params Object, you can add any parameters you want to eventually in the event data object. If you are don’t Progress page_location parameter, you will need to add it to the tag (see below). You can also provide custom event_name parameter, and the client form will open by default to page_view If you don’t.

The client_id It is automatically generated as a unique random value for each request.

legal notice: This means that we do not measure Users who use braces but rather single hits And whether it is prohibited or not. I wanted to ignore Users Simply because I don’t want to start setting cookies or fingerprints just for the purpose of this exercise.

Finally, a pixel request is sent to your server container, which captures it and creates an event data object with the parameters:

event data object

Set up GA4 tag

In the server container, you can then configure the GA4 flag to activate when that specific event data object is created. for this purpose, I recommend creating a new data stream for this data only. This way you don’t pollute your marketing analytics data with ad blocker coverage.

GA4 day

As you can see, I’m refining the visitor’s IP address (I consider that a required setting in all GA4 scaling).

Remember to add the dataflow measurement ID to the tag. You don’t need to add any of the custom parameters from the pixel request – they will be automatically sent to GA4 only by virtue of their being in the event data object.

Finally, here’s what the launcher looks like:

Server Dedicated Player

In Google Analytics 4 you remember to configure custom parameters as custom dimensions.

GA4 custom dimensions

Test setup

Once everything is in place, you can check the server container preview mode while your site’s homepage is loading.

ads-min.js and 4dchk

You should see a request for /ads-min.js Soon followed by a request for /4dchk pixels.

In Google Analytics 4, you should see your events fall into the real-time report.

Page view event

Note that everything else in GA4 should be pretty much a flat line. Since you are not using the recommended SDKs, you are also not properly measuring user activity and interaction. But we don’t care about that – we only care about events.

You can then aggregate them into any reports you wish using a file explore Google Analytics section 4 or so Google BigQuery If you configure the export for this data stream.

Also remember to test with a variety of blockers! For example, this is what it looks like in browser network requests when I load the homepage using Brave Browser:

all banned

As you can see, all three parameters have a value true, which indicates that in Brave, everything is blocked.

However, in Firefox Private Windows:

Firefox private windows

Nothing is blocked!

Well, I’m using ads-min.js As a bait file, the list of filters used by Firefox ( does not match the file names but rather the trace domains themselves. And although GA and GTM are not technically preventedtheir main roads Bright, which means it will not work in Firefox.

Fill It means that the methods are there to avoid pages from breaking due to reference errors, but they are overwritten in a way that prevents them from doing what they were meant to do.


You may have noticed the number of warnings heard in the article. This is due to the detection of ad and content blockers it’s hard.

Blockers are designed in such a way that they are as unobtrusive as possible, and while they rarely succeed in being transparent, they make the code difficult to detect and tune.

I’m sure there are more complex ways to discover different blocking mechanisms than the ones I’ve presented in this article, but the purpose of this article wasn’t to show you how reveal Rather, how? Measurement their influence.

With a Google Tag Manager Server container, you have an inexpensive API endpoint that is relatively easy to set up. It works on your domain, so the ad blocker detector itself is not blocked by ad blockers.

It’s a nice use case for a server container, again.

With this method, you can selectively prevent server tags from activating if the user is using an ad blocker. Of course, it won’t help in use cases where the user uses blockers just to block them Which Extraneous scripts from launching them in their browser. It is up to you to decide how far you want to take your respect for the user’s wishes.

If you’re curious, I’ve found in my tests the following:

  • ~ 7% Page load times where it happened Google Tag Manager It was forbidden.
  • ~ 10% Page load times where it happened Google Analytics It was forbidden.
  • ~18% Page load times where it happened ads-min.js Thus, by proxy, advertisements been banned.

Please let me know in the comments if you have questions about this setting or comments about ad/content blocking in general.

Source link

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button