Use closures for custom JS variables in Google Tag Manager

You do know what custom JS variables in Google Tag Manager are, don’t you? So I won’t waste neither your nor mine time providing a sprawling explanation for these fundamentals (see my previous post). If you don’t, then, probably, that’s not the best guide for getting started with GTM basics. There are lots of excellent blogs giving sugar-coated knowledges of this kind (if you still prefer official Google documentation, here it is).

Here we’ll try to look at a little bit more complex usage of these variables. So, in this post I’d like to demonstrate how you can leverage custom JS variables in Google Tag Manager for JS closures.

use closures for custom JS variables in Google Tag Manager: power-of-js

Before we begin – custom JS variables in Google Tag Manager

I guess we still need to do a quick cruise through basics. Here are three simple things you should learn about custom JS variables in Google Tag Manager:

1. it always should be an anonymous function

In other words, it should look something like

2. it always should have a return statement

3. you can use other GTM variables within a custom JS variable

All the above (and especially the 3rd point) makes custom JS variables a cross-functional omni-purpose tool that is able to raise to almost any occasion. Yes, almost. There are certain situations when you should use a custom HTML tag instead (for instance, when dealing with dataLayer).

Please mind the 2nd point. A custom JS variable should always return something – a value, other GTM variables. And even other functions. But what’s the purpose of a function returning another function? Check out the next paragraph!

What is a closure in Javascript

Yet again, lucky for me (and you) there’s a topnotch guide on JS closures written by MDN web docs team. Be sure to check it if you want to get a full insight on closures. Let’s pick the definition:

closure is the combination of a function and the lexical environment within which that function was declared.

Now, let’s try to explain it other words.

A closure is when you first declare a certain value (say, using another GTM variable), next write a function A (inner function) that does something with that value, and then you wrap it in another function B (outer function) returning the code (!) of function A. Here’s how it looks:

use closures for custom JS variables in Google Tag Manager: what is a closure

A simple example of a closure in GTM

Now, you may be wondering why the hell you need all this – a function returning a function? But let me demonstrate you how useful this can be in GTM.

Suppose, you need to create a cookie (or a browser storage item) when a user performs a certain action on your site. What you would usually do is create a custom HTML tag containing necessary code and fire it once the event occurs. Easy, right?

But what if you need to perform this for other five (or twenty five) user’s actions. Would you create a bunch of HTML tags with almost identical content? More than that, as you may know, it is recommended to check whether or not browser storage/cookies are available before trying to use them. Would you copy/paste the checking code into each HTML tag? I believe there’s a better approach.

What you can do is to create a single custom JS variable that does the job and invoke it every time you need it. Here’s an example for creating an item in a browser storage (local storage particullary):

You can use your dataLayer variables for name and value variables. Thus, you can set different values according to different dataLayer content. Let me explain some technical details concerning this approach. So, this is how it works:

  1. You create a custom JS variable with a certain name (let’s say, it is “myVar”) and paste the code above into it.
  2. GTM assigns the code of the function A (which is returned by function B) to a variable called “myVar” with the respective lexical environment (which is, in our case, “name” and “value”)
    In other words, it looks like myVar = function B code + lexical environment. And that is a closure.
  3. When the variable containing the function B is invoked, an item with name of {{name_for_your_LS_item}} and value of {{value_for_your_LS_item}} is created.

If localStorage is not available, the function will return undefined when invoked. Finally, the only recourse you have is to invoke your custom JS variable at the right time and place.

Invoking the variable

If you have a GA tag firing once the event arrives, you can use hitCallback field for the variable. Thus, once the your UA tag is finished processing, a localStorage item will be created.

use closures for custom JS variables in Google Tag Manager: ex2

Please mind that if you’re using a GA settings variable, you should add “hitCallback” field to it, not to the GA tag you’re firing.

However, there’s a caveat here. If the GA tag fails to fire, the function responsible for creating an item won’t be called. That is where the “Tag Sequencing” option can be of use. But in this case you will have to create a custom HTML tag containing the invocation statement for the variable like this.

You need to use it in your GA tag like this:

use closures for custom JS variables in Google Tag Manager: ex1

Here I fire a certain custom HTML tag just right after my UA tag fires.

Other options for the variable

If you want to have an opportunity to manually set arguments for the function, your variable should look like this:

Please mind that in this case you MUST use a custom HTML tag for invoking the variable since you can’t use arguments with hitCallback field. Then the invocation statement will be like:

Finally, if you just want to have a function checking the availability of cookies/browser storage, use this:

Call this variable whenever you need it.

More examples

I’ve already mentioned JS closures for custom JS variables in Google Tag Manager in other guides of mine. Here’s how you can use it for sending events to Facebook using Google Tag Manager or sending events to Yandex.Metrica

Things to consider

Besides those performance considerations and common mistakes described in MDN guide (you’ve already read it, haven’t you), there’s another thing you should be aware of. Please mind the current lexical environment of the variable when invoking it. What I mean here is that your dataLayer variables ({{name_for_your_LS_item}} and {{value_for_your_LS_item}}, see the very first example) used inside the function can vary depending on different dataLayer events.


Phew! I must admit writing a 1233 word guide wasn’t that easy, especially after a long break. Anyways, I hope you’ll find it useful for your everyday needs. Use the comment section for letting me know of any issues appearing while implementing this solution.

Tag Manager , , ,