Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Track Element Viewability With JavaScript Or Google Tag Manager

As you might know, sponsored advertisements are one of the things that are funding The Polyglot Developer and everything it accomplishes, so keeping sponsors happy and supplying them the metrics they need is very important. However, in most circumstances, more specifically when it comes to banner creatives, page views is not enough. For example if your sponsors or potential sponsors asked how many impressions each of your advertisement zones gets, you can’t just list off the page views that those particular pages get because how do you know if the user actually saw the advertisement?

I’ve heard a few names when it comes to element impressions. Some call it element or image visibility, and some call it viewability. It doesn’t really matter as they are both trying to determine if the user has actually seen the image or element on their screen.

In this tutorial we’re going to take a look at tracking if users have seen a particular image or set of images using simple JavaScript as well as an alternative method that links directly with Google Analytics (GA) called Google Tag Manager (GTM).

Like I mentioned, we’re going to explore two approaches. It is good to have options in case you don’t want to be locked into any particular service and would like to manage these kind of things on your own.

Tracking if an Image on the Website was Seen using JavaScript

The first approach we’re going to look at is a pure JavaScript approach that can be integrated into any website or content management system theme. Take the following example which might exist in an index.html file:

<html>
    <head>
    </head>
    <body>
        <div style="height: 5000px; width: 100%">
            <img class="advertisement" style="position: absolute; top: 900px; width: 250px" src="nraboy.jpg">
            <img class="advertisement" style="position: absolute; top: 3000px; width: 250px" src="nraboy.jpg">
        </div>
    </body>
</html>

On this very simple website, I have two images with a lot of height between them. In other words neither of these two images are immediately visible without scrolling and neither of these images are visible at the same time. We want to find out when these images are within a viewable region of the screen.

It is important to note that we’re not trying to figure out if the DOM element is visible or invisible through CSS. We’re trying to figure out if these elements are within our view port.

For this example we’re going to use a mixture of libraries, but if you are really good at JavaScript, you could get away with none.

Within this index.html file, include the following:

<html>
    <head>
    </head>
    <body>
        <div style="height: 5000px; width: 100%">
            <img class="advertisement" style="position: absolute; top: 900px; width: 250px" src="nraboy.jpg">
            <img class="advertisement" style="position: absolute; top: 3000px; width: 250px" src="nraboy.jpg">
        </div>
        <script>
            function isElementInView(element) {
                var elementBoundingBox = element.getBoundingClientRect();
                var elementTopY = elementBoundingBox.top;
                var elementBottomY = elementBoundingBox.top + elementBoundingBox.height;
                return elementTopY >= 0 && elementBottomY <= Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
            }
        </script>
    </body>
</html>

Assuming we pass an HTML element to the isElementInView function, we want to run a few calculations. First we want to figure out where the element sits on the screen, which can be accomplished by using the getBoundingClientRect function. The top property represents the distance from the top of the screen, which in our case would be 900px or 3000px and the bottom property represents the height of the element added to the top property.

As we scroll up and down on the page, the top and bottom values will change, staying either positive or negative.

To determine if an element is viewable or visible, we first make sure that the top of the element is not negative. If it is negative it means that we’ve scrolled too far down beyond the element. We also determine where the bottom of the element sits in regards to the viewport height. The clientHeight which is the page height, doesn’t always represent the innerHeight so we’re taking whatever is smallest. If the element or image falls between these measurements, it is viewable. Currently, this calculation represents 100% viewability, meaning the whole element must be viewable, not just part of it. If you wanted to get fancy, you could say it is viewable if it is within a certain percentage.

Now that we can calculate what is or isn’t visible, we need to apply it towards our elements. Take the following method:

function checkElementViewability() {
    var elements = document.querySelectorAll(".advertisement");
    for(var i = 0; i < elements.length; i++) {
        if(isElementInView(elements[i])) {
            console.log("Element " + i + " is viewable");
        } else {
            console.log("Element " + i + " is not viewable");
        }
    }
}

In the checkElementViewability method we are looping through each element that has the advertisement selector. This can be modified depending on how you want to track your elements. For each element we run it through our isElementInView function and print out the result.

This is where we start making use of external JavaScript libraries.

Take the following modified index.html file:

<html>
    <head>
    </head>
    <body>
        <div style="height: 5000px; width: 100%">
            <img class="advertisement" style="position: absolute; top: 900px; width: 250px" src="nraboy.jpg">
            <img class="advertisement" style="position: absolute; top: 3000px; width: 250px" src="nraboy.jpg">
        </div>
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
        <script>
            function isElementInView(element) {
                var elementBoundingBox = element.getBoundingClientRect();
                var elementTopY = elementBoundingBox.top;
                var elementBottomY = elementBoundingBox.top + elementBoundingBox.height;
                return elementTopY >= 0 && elementBottomY <= Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
            }
            function checkElementViewability() {
                var elements = document.querySelectorAll(".advertisement");
                for(var i = 0; i < elements.length; i++) {
                    if(isElementInView(elements[i])) {
                        console.log("Element " + i + " is viewable");
                    } else {
                        console.log("Element " + i + " is not viewable");
                    }
                }
            }
            checkElementViewability();
            $(window).on("scroll", checkElementViewability);
        </script>
    </body>
</html>

When the application loads we run the checkElementViewability method to see if anything is initially in view. In our example, that is unlikely.

Using jQuery, we can add a scroll listener. When a scroll event happens, we execute the checkElementViewability and see if any elements are now in view. There is a flaw with this however. When we scroll, it will be continuously executing the checkElementViewability which could severely slow down your website. It is particularly bad if you are making frequent HTTP requests based on the viewability of your components.

Instead, we can create a debounce to act like a throttle. There are plenty of ways to create a debounce, but I found the easiest to be with the Lodash library. With Lodash, we can make the following minor change:

$(window).on("scroll", _.debounce(checkElementViewability, 250));

Now there will be a 250 millisecond delay, not in the scroll itself, but in triggering the checkElementViewability method.

Realistically, you wouldn’t just print out whether or not the element is visible. You’d probably trigger an event with Google Analytics and track it as an element impression rather than a page view.

Using the Google Tag Manager to React to Element Visibility Events

If JavaScript isn’t your thing and you’d prefer to use a WYSIWYG type of experience, you might want to use Google Tag Manager instead. With Google Tag Manager (GTM) you can create triggers for certain events that happen on your web page. These events are handled through tracking codes similar to Google Analytics. I think the selling point behind GTM is that you can make changes to your tags without touching your website.

The process that we’ll use is as follows:

  1. Create an element attribute variable with Google Tag Manager
  2. Create a trigger for element visibility events
  3. Create a tag to link the trigger to Google Analytics

Because we will be sending data to Google Analytics we need to determine what to send. We need to create a custom variable with custom element attribute information. Think of the following adjustments to our HTML components:

<img class="advertisement" gtm-tag="image-1" style="position: absolute; top: 900px; width: 250px" src="nraboy.jpg">
<img class="advertisement" gtm-tag="image-2" style="position: absolute; top: 3000px; width: 250px" src="nraboy.jpg">

In the above example, gtm-tag is a custom attribute. It can be named whatever we want, but at least we’ll be able to remember what it is by prefixing it with gtm-. The value is something to differentiate it in your Google Analytics. It might not be useful to track all advertisement creatives the same because you may want to track performance individually.

Inside your Google Tag Manager workspace, choose to create a new variable.

Google Tag Manager, Auto-Event Variable

You’ll want to create an Auto-Event Variable and define an Element Attribute. If you’re going to follow my example, the attribute name should be gtm-tag.

Next you’ll want to create a trigger. The trigger will do all of the heavy lifting.

Google Tag Manager, Element Visibility Trigger

You should be creating an Element Visibility trigger and base the trigger off a CSS Selector. If you’re following my example, the selector should be .advertisement with the period prefixed. This means the trigger will be set on every element that has that particular selector. Because you have potentially more than one element, make sure the event triggers once for each element and not once per page. If you don’t have any DOM changing events, there is no need to watch for changes. Our example has none of these events.

Before we create the tag, we need to create a variable for Google Analytics.

Google Tag Manager, Google Analytics Variable

When creating your variable, choose Google Analytics Settings and provide your tracking code.

The final step is to create the tag which tells the trigger how to respond.

Google Tag Manager, Google Analytics Tag

When creating the Google Analytics - Universal Analytics tag, you’ll want to make sure Non-Interactive Hits are enabled since we won’t be interacting to clicks or similar. You can use each of your custom variables for different parts of the Google Analytics events.

After you publish your workspace and add your GTM snippets to your website, you should be able to track the viewable impressions.

Conclusion

You just saw two different ways to track whether elements became viewable on your web pages. Like previously mentioned, this is different than a standard page view because page impressions don’t necessarily mean that the user saw a particular element on the page. Knowing the metrics behind your element impressions is critical for advertisers and sponsors because this is the type of information they’ll need when it comes to performance and whether or not they will sponsor you.

If you have better ways to accomplish what I’ve done, I’d be happy to hear it in the comments!

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Search

Follow Us

The Polyglot Developer

Subscribe

Subscribe to the newsletter for monthly tips and tricks on subjects such as mobile, web, and game development.

The Polyglot Developer

Support This Site