Using Google Tag Manager For Visitors Without JavaScript

March 23, 2015
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:


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:

Screen Shot 2015-03-13 at 11.17.31 AM

Added the Variable to the Custom Image Tag:

Screen Shot 2015-03-13 at 11.24.16 AM

And loaded the page with JavaScript disabled, Google Tag Manager would try and fetch the interpreted value:

Screen Shot 2015-03-13 at 11.24.51 AM

Note that if we load the page with JavaScript enabled, the variable is undefined:

Screen Shot 2015-03-13 at 11.29.24 AM

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.

Screen Shot 2015-03-13 at 11.31.34 AM

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:

Screen Shot 2015-03-13 at 11.35.28 AM

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:


The UA Number of the account we’re sending the hit to


The version number of the protocol we want to use (currently only version 1 is available)


The hit type (pageview, event, etc)


The full URL of the page we’d like to say a pageview has occurred on


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: