Using Google Tag Manager For Visitors Without JavaScript
Sometimes, it can be useful to track browsers that do not execute JavaScript, whether we’re tracking hits, email click throughs, or other image tags. This can help your organization gauge how many users cannot make use of JavaScript-powered features, determine if things like headless browser-based bots are frequently scraping your site, and understand more about the differences in what Google Analytics records versus what your server logs might show.
Fortunately, Google Tag Manager has some fantastic built-in features to make doing this a snap, and you may not even realize that it’s already implemented on your site!
What’s an Iframe?
An iframe is kind of like a popup but embedded in the page. They are used for lots of things, like web analytics, ad targeting, and embedded 3rd party content.
Google Tag Manager’s installation instructions include an iframe that you by default include on your site. It’s one of the reasons that GTM is added in the BODY of your site and not the HEAD.
Google Tag Manager uses its iframe for something a little different: it uses it to fire Custom Image tags when a users browser doesn’t execute JavaScript. You can use this feature to measure behavior for users not running scripts on your site.
How It Works
The iframe is wrapped in a <noscript> tag; this is a special kind of tag used to give browsers special instructions for when they do not execute JavaScript. You may have seen one before wrapped around something like “Please enable JavaScript to properly view this page”. If JavaScript is enabled, the contents of the <noscript> tag are ignored.
When a browser doesn’t have JavaScript enabled, it reads the HTML in that tag, causing the browser to request the iframe from Google’s servers. When Google gets a request for that iframe on its server, it compiles all of the HTML needed for the Custom Image Tags it should fire and sends it back. The browser then parses the HTML, requesting the images in the tags, generating a hit.
Now, it’s important to note, this only works for Custom Image tags. JavaScript tags will not do anything, as the browser doesn’t execute JavaScript, and Google Tag Manager doesn’t appear to try and serve Custom HTML tags at all.
A Simple Example
Let’s walk through a simple example; let’s say that every time a user not executing JavaScript loads the page, we want to send a hit to a simple hit counter, like Pixel Ping. The first thing we’ll need to do is create a Custom Image tag, and then set the Image URL field to something like this:
//www.alicesemporium.com/pixel.gif?key=noscript-pageview
Setting our Firing Trigger to All Pages will tell Google Tag Manager to add this tag to every page, resulting in a request for pixel.gif?key=noscript-pageview on each pageview, which our server would, in turn, interpret as a hit and increment our counter for us.
However, this would include pages where the user had JavaScript enabled. So how can we only want to fire this hit when the user isn’t executing JavaScript?
That’s where the data layer comes in.
Wait, what? The Data Layer, without JavaScript?
Normally, when we talk about the data layer, we’re referring to JavaScript object that Google Tag Manager creates on the page. However, when a user isn’t executing JavaScript, we need another way to store and access information. Google Tag Manager lets us do this by adding query parameters to src attribute of the <noscript>’d <iframe>.
Query parameters are key-value pairs of text that appear after the ? in a URL, paired by equals symbols (=) and separated by ampersands(&). They are used by web applications and web servers in order to modify the content that the server sends back to our browser.
Google Tag Manager lets us add our own key-value pairs to the URL to replicate our data layer object when a user who doesn’t execute JavaScript loads the page. Any key-value pair we add will be accessible in the Google Tag Manager interface as a Data Layer Variable, where the variable name is our key. For example, if you added this:
Then set up a Data Layer Variable like this:
Added the Variable to the Custom Image Tag:
And loaded the page with JavaScript disabled, Google Tag Manager would try and fetch the interpreted value:
Note that if we load the page with JavaScript enabled, the variable is undefined:
Only Firing The Tag On Browsers Without JavaScript Enabled
By adding “noscript=true” to the URL of our <iframe>, we will have a Data Layer Variable that is only ‘true’ when JavaScript isn’t enabled. Remember, this iframe will only load if JavaScript is not enabled.
Using this, we can create a Trigger that fires our tag only when the user isn’t executing scripts.
Now, we can change our Pixel Ping Image URL back to our initial value, add our firing trigger, and when we load the page with JavaScript enabled, we’ll see the request:
Update: As Simo Ahava noted in the comments below (as Duncan had noticed in the comments on Simo’s blog post about the topic), there is a simpler way to do this without modifying the snippet; simply create a Custom JavaScript Variable that returns True. Since it will always be undefined in the context of a browser that doesn’t execute JavaScript, it works just as well as adding noscript=true, without requiring you modify your snippet. Here is what this would look like:
// Variable Noscript function() { return true; }
Using Dynamic Data Layer Values
We can also make our data layer variables dynamic by changing the value in our key-value pair in the code on our server. This requires some server-side logic, where you’re either pulling information from a cookie or generating the information yourself. This really opens up what we can track with this feature.
An Advanced Example
For example, if we wanted to track a pageview in Google Analytics when a user doesn’t have JavaScript enabled, we’d need some dynamic values to do it properly. The documentation specifies that we need the following values, at a bare minimum:
tid
The UA Number of the account we’re sending the hit to
v
The version number of the protocol we want to use (currently only version 1 is available)
t
The hit type (pageview, event, etc)
dl
The full URL of the page we’d like to say a pageview has occurred on
cid
A user identifier used to group hits into sessions
The tid, v, and t parameters all have static values, but the cid and dl values are dynamic. We can populate these values dynamically on our server:
<pre”>
Side Note:If you can’t populate your cid dynamically, use the built-in Random Number Variable instead; this Variable will still work. If you use a static number, all your hits will be associated with one user, and since Google Analytics stops processing hits for users after they’ve sent 200,000 hits in a day, you could accidentally hit this limit and stop recording data. You can also try and come up with a user-specific value; this example would create a new user in every session.
We could do the same for our dl value, but Google Tag Manager makes it easy for us: enabled built-in Variables are accessible when the page loads, including the Page Variables like Page URL and Page Path. Google Tag Manager populates these by parsing the referrer when the browser requests the iframe content (thanks guys!). We can use the built-in Page URL variable for our dl value:
We could hard code our UA number into the tid value, but Google Tag Manager also supports any other Variables you have defined in your container that do not depend on JavaScript and are available as soon as the page loads. This includes Constants and Lookup Tables, which we would prefer to use for our UA Number instead for improved maintainability.
Our v and t values (API version and hit type) won’t change, so we can add those in statically.
Finally, we can use the same ‘Noscript Is True’ Trigger to fire our pageview.
And there you have it; you’re tracking Pageviews from browsers that don’t execute scripts.
Note: This method will not track ALL bots and spiders, just those that request external resources loaded on the page, but do not execute JavaScript. If you want to track everything crawling your site, I’d suggest either parsing your server logs or firing Google Analytics pageviews directly from your server..
Have you ever needed to track something in a situation where JavaScript wasn’t an option? Share your solution in the comments below.