Michael Sinner – Digital Analytics Consultant

Track Ezoic Ad-Exposure via GTM for more Transparancy

Ezoic Ads has quite a success story and became quickly the Monetization-Blogosphere’s darling. With AI to boost your ad moneys from websites you build mainly for monetization reasons. There are all the great reviews, showcases and stories you’ll find on the web. Like on where it all started for me, when I first heard of Ezoic. Quickly I realized there is one major concern I have with AI in general that just bubbled up when I implemented Ezoic the first time in a WordPress blog:

  • AI is intransparent in its decisions and outcome (in this case of automized ad display, as every client will have a different amount of ads displayed, and therefor we have no clue what exactly is the result)

Unfortunately the human nature (at least this applies to myself) is curios. I need to know what why and how something happened. Can you just rely on the Ezoic systems that there was „just the right“ amount of ads displayed to your users? How many ads were displayed per user on a single page? Which ad-spaces were empty and which not? Is my content overcrowded with ads?

Lets find out. By implementing some code and track the s**t out of all the ads, that are displayed to my websites visitors ūüôā
(no, not on this page though; no moneys for me here)

How many ads are optimal?

Lets first dig into the actual motivation on this post. It’s not all just about the knowledge how many ads my users see. Sure, thats really interesting to know, but whats the business case?

To answer the question of optimal ads per user or per page, you will quickly realize its not 42. No. Not even a certain number. Its a rather a rate of number of ads per user per time. Often a blogger will draw a line of 6, 4 or some other Number which they feel comfortable with. However thats too much of personal bias and so on. Which I found myself in, when I first thought about adding display ads to one of my blogs. Users mustn’t see too many ads and must be able to access the content first. As I put a crazy amount of time and effort to create content.


There actually is a huge post on this whole optimal ad count topic on Ezoic’s blog. Yes, it is actually a very good read with lots of insights that is way more than a „lets put some thin content so we have something“-blogpost: How Many Ads Are Too Many?

And with this I’ll close this little side-topic without digging deeper. Lets focus on the main question at hand.

How can I track the amount of ads displayed with Ezoic in GTM?

With Google Tag Manager (GTM) there is a little framework I installed to first analyze the amount, size and meta of ads displayed on a page to a client. This first check creates a „report“ and pushes all the information back to my Data Layer. Second I populate all the information to Google Analytics (GA) via Enhanced Ecommerce Tracking and Internal Promotion Tracking. This way I take advantage of native reports in the GA web interface (well, if you actually want to use this…). But even better: this includes a batching of all the data into a single request. As we will see, the amount of data tracked can quickly explode here, and we do wan’t batches. Right?

Very First: Challenges and Caveats

Now before we get into the code. You must know this. We will built a code that is prone to fail, as we anchor all our information on CSS selectors and HTML DOM information that Ezoic dynamically renders into a page. There are certain templates Ezoics code uses to embed the ads. But those will change as they update and improve their templates. And then this GTM code will fail. I have no clue when this will happen and how much effort there will be to maintain this code in GTM. I’ll keep you updated though, as I see something break in my data and code.

There is also one more challenge we will have to face. The dynamic nature of ads that Ezoic beds into your pages. Not all ads are displayed exactly on page load, ready or any other state. Even after some time the ads are reloaded, updated and empty spaces are filled and filled spaces are emptied. This challenges our tracking, but we’ll get to this in a moment.

First: Analyze the amount of ads displayed

Create a HTML tag in your GTM. The following code will analyze a pages DOM and look for ezoic ads. All ad spaces that are found are populated into an array of objects. With this properties:

  • index: a simple counter per ad space
  • width: the HTML objects property „scrollWidth“ which tells us the actual size
  • height: same as width, you get it
  • placement: the HTML objects property from the dataset directly on exactly the object found
  • comments: this contents all the HTML comment information from the object found. Including the objects parents comments and all further comments inheritated. This is implemented because Ezoic facilitates HTML comments to push meta information on ads that is very interesting and useful.

Second: React and Read the Data

To facilitate the data we got from the „Transparancy Report“ HTML tag we need some basic „groundwork“ GTM variables.

Basic Variables (Data Layer Variables):

  • dataLayer.ezoic.adImpression (simply map this Data Layer Var to „ezoic.adimpression“ which is populated in the tag above)
  • dataLayer.ezoic.submittedAdsCounter (simply map this Data Layer Var to „ezoic.submittedAdCounter“)
  • static.ezoicAdsCssSelector: This is¬†the „core“ item which is used to identify ad placements from Ezoic. Prone to fail, as this will change over time. As of now (2020-08-05) the content is:¬†[id*=ezoic-pub]

More complex Variables:

These three JS Variablers we will need in a second, just bear with me.

JS Variable Name: „js.ezoicEecPromotionImpression“

(this will create an object that is ready to use in GA’s EEC tracking)

JS Variable Name: js.ezoicVisibleAdsCounter

(this will use the same CSS selector as the main ‚Transparancy Report‘ HTML tag and simply¬†count¬†the visible ads)

JS Variable Name: js.ezoicAdUpdated

(this returns whether the count of visible ads is greater than the last known counter when ad-impressions were submitted to GA)

The Timing Challenge

As already mentioned there is a major challenge that we still need to tackle. Brace up, as we discuss some ideas on how to overcome this. The ever so dynamic nature of Ezoic ads. Which just can’t stay still and change in their size and content, after load and from second to second as the client browses a page.

Mainly because of the GTMs queueing system, we interact in loops of events that just so happen all the time. Page loaded. DOM ready. A click, a scroll and so on. But there is no single clear event on when an ad is loaded, displayed or updated. So we again have to build some adapter workaround countermeasure, which again comes with all the disclaimer. One more time I ask you to build error prone code.

There are two options I see to work around this issue.

  1. Facilitate mutation observer events: use the CSS selector we already have to facilitate mutation observers as an API to trigger the ‚Transparancy Report‘ tag.
  2. Use static triggers and events you already have and check if Ezoic ads changed between two events.

The first approach is much more detailed and will give you the most insights. However this comes with the cost of added complexity (adding hazard of shaky code), browsers compatibility issues and performance that will increase the load on your clients browser. Therefor I didn’t implement any such solution and will showcase just the latter approach.

Instead I use the following system to trigger my Ezoic ads information loop. So the main GTM Tag to analyze and report what ads are displayed has two triggers actually.

a)¬†Some pretty early event (such as Pageview, DOM Ready,…) where hopefully some ads are already visible.

b) Any event, later then the first triggering event, where the amount of visible Ads changed.

This is as tricky as its vague in description. The reason is, that the very first ads will probably load way later than the actual page is displayed to the user. Therefor we need the variable, which simply gives us an Integer counter of how many ads are visible at this exact event in our GTM queue (dataLayer). The first (and initial) transparancy report mustn’t start prior this counter is >0. Otherwise we will bloat our GA data with empty-ad-space information. Though maybe its also helpful, so it’s also possible to just track an initial status (without considering the counter). This is absolutely open for discussion and to be decided per individual case.

Then there is this second trigger, which is very vague described as „any event, where ad count changed“. This setup will only work, if you already know there are more events to come on every relevant pageview. Or you’ll have to implement a timer trigger or similar.

In my case there actually is a 10sec trigger already installed to track basic interaction rates with my blogs content. Just a short check if the user already dropped out or is still there, reading the content. Also there are more clicks and interactions tracked, so I generally assume there are „enough“ events to be queued and trigger my Transparancy Report tag. This is the actual trigger:

For some reason the GTM interface won’t keep this english and always translates the text to german; even though the rest is english

And thats all the workaround to give an educated guess what goes on with my page and all the ads. Now what to do with all this data?

Finalize with a pinch of EEC Tracking

The data streams in¬†the ad information pipeline. As the pages load and with every event the system checks for changes and reports if something happened. If so we receive dataLayer updates. With an array full of ad display objects and properties. Now arrays with multiple objects are a multidimensional thing but GA in its basic setup only expects two dimensional observations („a [pageview|session|event] happend with the following properties and values“).¬†EEC to the rescue!

Fortunately around 2014 already GA took care of this. With enhanced ecommerce and the option to fill index based observations into single dimensions (like a list of products or internal promotions). Which is exactly what we need to track multiple ad observations on a „flat“ single pageview interaction.

Therefor I created a little translation adapter script, which will take the Ezoic ad information and parse it into the EEC internal promotion JSON representation. This is the GTM variables code (custom JS variable): „js.ezoicEecPromotionImpression“ (see above)

This is the final configuration of my GA event.

Now what will this look like in GA when all this GTM code is published onto production?


In this post I created the following steps to analyze the ad exposure to website clients with GTM.

  1. Create the CSS selector based HTML/JS tag, which check the page for ads. These observations are pushed into the dataLayer.
  2. Create meaningful triggers that work for your case, where I only described some options and caveats.
  3. React to the transparancy reports from the first step and send the data to GA, e.g. with GA enhanced ecommerce and internal promotions.

Google DataStudio erste Schritte mit Google Analytics Daten

Bis vor kurzem war Googles Data Studio ein geschlossenes System.¬†Spannend wurde es, als Google dieses Jahr das Data Studio als offene Version¬†ank√ľdigte. Damit konnte man unabh√§ngig vom Analytics 360 Programm auf ein cloudbasiertes BI Tool zugreifen, welches Datenquellen wie SQL-Datenbanken, Google Spreadsheets, AdWords, Google Analytics, etc. verbindet. In einem Dashboard werden alle Daten nebeneinander visualisiert. In diesem Beitrag¬†zeige ich die Kernfunktionen in einem Showcase von Funktionen wie Segmentieren und Pivotieren sind per se nicht verf√ľgbar,¬†mit ein paar Tricks klappt aber auch das. (mehr¬†…)

Eigenen Linkshortener mit eigener Domain und Statistiken in 10 Minuten anlegen

Wem oder als Namen beim URL k√ľrzen nicht ausreicht. Sollte¬†man einen eigenen Brand nutzen wollen, ohne¬†auf Statistiken¬†zu¬†verzichten, so bietet sich eine eigene Shortdomain an. Mit einer einfachen Weiterleitung kommt man schnell ans Ziel.

Zwar kann man bei eine Custom Domain registrieren und den DNS Eintrag seiner Domain auf eine IP von konfigurieren, leider teilt man sich dann trotzdem den Namespace mit allen anderen Nutzern. Möchte man sich beispielsweise micha.el/test im Bitly Interface anlegen, so ist dies nicht möglich. Denn ist bereits vergeben.

Hingegen hat noch nicht einmal die Möglichkeit eine Custom Domain anzulegen. Auch sind eigene Pfade nicht vorgesehen.

Die Lösung ist so naheliegend, dass man nicht direkt drauf kommt. Mit einer einfachen 301-Weiterleitung, die man schnell in der .htaccess Datei konfigurieren kann, bekommt man Custom Domain und einen eigenen Namespace schnell hin.

Wer zus√§tzlich noch eigene URL Pfade¬†verwenden m√∂chte (alles nach micha.el/…) kann dies mit l√∂sen.

Wir benötigen:

  • eine eigene kurze Domain (registrieren und mit einem Host verbinden, z.B. ein Hostingpaket bei,, usw.). Beispiel: micha.el
  • Zugriff auf die .htaccess Datei im Ordner eures¬†Servers (z.B. per FTP Zugang)

Wenn bisher keine .htaccess Datei vorhanden ist, dann legt folgende Textdatei an und speichert sie als .htaccess ab. Andernfalls ergänzt die bestehende .htaccess um diese Zeilen. Vorsicht: diese Datei ist nur sichtbar, wenn ihr versteckte Dateien anzeigen lasst.

Mit und eigener Domain weiterleiten

Mit folgendem Code kann man eine mit¬†Google gek√ľrzte URL nutzen, aber keinen eigenen Pfad vergeben.

Ihr k√∂nnt nun mit eine URL k√ľrzen und den Shortcode an eurer eigenen Domain verwenden. Wenn euch als Short-URL z.B. „“ angibt, dann wird „micha.el/1234“ eure Short-URL mit eigener Domain sein. Der Pfad muss 1:1 √ľbernommen werden.¬†Und schon seid ihr fertig.

F√ľr Fortgeschrittene: Eigenen Pfad definieren

Sollte man zusätzlich einen eigenen Pfad vergeben wollen, z.B. micha.el/CallToAction, dann ist dies mit Bitly möglich (aber nicht mit

Legt in eine URL an und vergebt eine zum Teil kryptische Kurz-URL an. Der erste Teil ist kryptisch, der andere entsprechend lesbar. Begr√ľndung folgt im Beispiel:

F√ľr die Ziel URL micha.el/CallToAction muss in Bitly folgender Link angelegt werden:

Der erste Teil (krypto123_) ist notwendig, damit ihr keinen Konflikt mit einer bestehenden URL bekommt. Der lesbare Teil wird beim Weiterleiten beibehalten und somit aus eurer Domain √ľbernommen.

Folgende Einstellung ist dann in der .htaccess Datei vorzunehmen

Der einzige Unterschied ist die Weiterleitung zu Dies ergibt sich aus der Domain und eurem selbst gewählten kryptischen Teil der URL.

Was passiert nun? Unser Aufruf der micha.el/CallToAction wird weitergeleitet an Das Ziel f√ľr diese URL habt ihr in Bitly zuvor gepflegt.

Wie verwendet man diese URLs? Ihr m√ľsst nur daf√ľr sorgen, dass der lesbare Teil in eurer Short-URL mit dem lesbaren Teil in Bitly √ľbereinstimmt.

Wenn ihr „micha.el/Beispiel“ verwenden m√∂chtet, dann m√ľsst ihr in Bitly „“ angeben, usw.

Die Logik sollte aus diesen Beispielen zu erkennen sein.

Kommentare sind willkommen!

Google Analytics nun unter dem „Privacy Shield“

Schon im Feb 2016 wurde eine Alternative zum gescheiterten Safe Harbor verhandelt: „Privacy Shield“. Bei Datensch√ľtzern als mangelhaft bewertet aber von Wirtschaftsverb√§nden und Unternehmen begr√ľ√üt (heise). Schlie√ülich brauchte man schnell wieder eine Grundlage um zumindest einen Rahmen zu schaffen unter dem man weiter agieren konnte. Wie gut dieser war ist erst mal zweitrangig gewesen, da der Entwurf nur eine H√ľlle mit Buzzwords war.

Nun hat¬†Google f√ľr Google Analytics (GA) vor zwei Tagen (29.08.) den Privacy Shield adaptiert und besitzt nun ein solches Zertifikat. Aber zu welcher Grundlage genau wird bei¬†Verwendung von¬†Google Analytics ein solches Zertifikat ben√∂tigt?¬†Ursache¬†ist das √úbermitteln von personenbezogenen Daten in die USA.

Es gibt zwei Fälle in denen personalisierte Daten mit Bezug zu GA verschickt werden.

  1. In einer Dimension zu Reportingzwecken, z.B. zur GEO-Lokalisierung. Andere Dimensionen d√ľrfen jedoch laut Nutzungsrichtlinien von GA nicht mit personenbezogenen Daten best√ľckt werden. Per anonymize=true kann in der Implementierung dieser Fall geschlossen werden.
  2. Bei der Kommunikation per HTTP und TCP/IP wird die IP-Adresse des Clients √ľbermittelt und kann ein personenbezogenes Datum sein (Auslegungssache?). Jedoch ist das im Web ein architekturbedingte Voraussetzung, da sonst keine Kommunikation zwischen Client und Server m√∂glich ist. Betrifft somit auch nicht nur Google Analytics, sondern jegliche Kommunikatino zu AdServern, ausgelagerten Dateien (Cloudspace und alle CDNs), etc. etc.

Wenn der 1. Punkt per Implementierung¬†behoben werden kann, wieso ist der 2. Punkt explizit bei Google Analytics ein so hei√ü diskutiertes Thema? Oder gibt es noch einen anderen Ber√ľhrungspunkt, den ich √ľbersehen habe?

Nicht zu vergessen ist schließlich der explizite Hinweis zum Safe Harbor innerhalb der Auftagsdatenverarbeitung zu Google Analytics.

Kommentare erw√ľnscht!

Google Analytics / Universal Analytics HTTP/URL Parameter Liste

Google Analytics √ľbermittelt mittels Measurement Protocol die Daten, was auf HTTP basiert. Das bedeutet man kann mit beliebiger Software den Verkehr im Browser und auch in der App abfangen und analysieren. Hier eine kurze √úbersicht √ľber alle Parameter im HTTP Request zu (Measurement Protocol) und /__utm.gif (klassisches Analytics). (mehr¬†…)

Google Tag Manager – Auto Event Tagging

Google Tag Manager Logo

Eine der wesentlichen Neuerungen an Google Analytics bzw. Google Tag Manager (GTM) die beim Google Analytics Summit 2013 vorgestellt wurden, war das Auto-Tagging. GTM erlaubt zwar Tags einfach in die Seite einzubauen ohne technische Ressourcen zu beanspruchen, aber Ereignisse bzw. Events m√ľssen nach wie vor erst implementiert werden. Und das bedeutet wieder einen Change Request an der Website, der von der Agentur oder sonstigen Dienstleistern erst mal eingebunden werden muss. Das Auto Event Tagging erm√∂glicht uns nun mit viel weniger Aufwand in sehr kurzen Intervallen Events zu erfassen. Hier eine kurze Anleitung. (mehr¬†…)

Google Analytics Summit 2013 Mountain View – AllesInAllem

google analytics summit babak pahlavan

Baba Pahlavan stellt die 14 Announcements vor

Alles in Allem war auch dieses Jahr der GA Summit bei Google eine riesen Party, bei der ein Feuerwerk gez√ľndet wurde. Nicht so gro√ü war es und stand etwas im Schatten der letzten Jahre, da es keine Ank√ľndigung wie Universal Analytics gab. Dennoch unheimlich spannend und an manchen Stellen PipiInDenAugen-Momente. Content Channeling, endlich! Account Management Write API – super! (mehr¬†…)

Mobile und Google Рwieso verträgt sich das so gut?

Google Mobile Studien Logo

Google Mobile Studien sollen aufklären, verraten aber nicht den wahren Hintergedanken des Konzerns.

76,5% Wachstum in Mobile Ads, 97% aller Smartphone-Besitzer nutzen das Internet, 92% benutzen Suchmaschinen mobil. Solche Fakten werden uns von Studien und Google um die Ohren geschmissen. Mobile ist das n√§chste gro√üe Ding! Ok, wenn es zumindest nach den Konzernen geht. Vertrauen funktioniert durch Studien, denn diese sind augenscheinlich objektiv und werden von unabh√§ngigen Instituten erhoben. Doch wieso steckt Google und Mobile so sehr unter einer Decke? (mehr¬†…)

Mobile vs. Desktop Nutzung – Infografik

Vergangenes Jahr (2012) habe ich eine Masterarbeit zum Thema „Reichweitenerh√∂hung von Nachrichten- und Medienportalen durch Einsatz mobiler Anwendungen“ verfasst. Die wesentliche Studie bestand aus der Auswertung von mobile und non-mobile Zugriffen auf die Websites meiner Probanden,, und In Kooperation mit den Websites habe ich interne Daten aggregiert und ausgewertet.

Das Ergebnis m√∂chte ich etwas verz√∂gert heute in Form einer Infografik und des (mehr¬†…)

Facebook und Google schaffen universelle Cookies

Pl√§tzchenzeit… ist vorbei. Nicht aber f√ľr Facebook und Google. Letzterer k√ľndigte bereits Ende 2012 an eine universelle Google ID auf den Markt zu bringen. Facebook hat diese Ank√ľndigung erst vor wenigen Tagen gebracht. Wir werden √ľberall erkannt und √ľberall werden unsere Daten an die zentralen Datensammelstellen √ľbertragen. Quasi eine Institution f√ľr Daten, sie wissen mehr √ľber uns als unsere Kinder es je erfahren werden. (mehr¬†…)