Google Tag Manager: The Lookup Table Macro

Having just come hot of the press with my latest article on GTM and Content Grouping which, to my delight, LunaMetrics had written an amazing tutorial on earlier, Brian Kuhn and the amazing Google Tag Manager development team came out with another incredible new feature: The Lookup Table Macro.

In software engineering, a lookup table is an array which takes away a layer of complexity in runtime computation, and replaces it with a simple value assignment based on array indexing. To put it simply, a lookup table looks through an array of source values, and assigns a value to the target depending on what the source value is. Well, maybe it’s easiest to show it in an image:

Lookup Table macro example

This is probably the most simple use case for the lookup table. The range of source values is derived from the custom JavaScript macro {{post_publish_date_month}}, which returns the month when the article the visitor is browsing was published. The lookup table goes through the possible values of the source macro, and it uses these values to assign the literal month name to the target macro, {{Post publish month}}.

NOTE! The source value (i.e. “When {{macro}} equals”) is case-sensitive!

Why use lookup tables

So why resort to a lookup table, when you can just add simple predicate logic to your custom JavaScript, and have it return the month name directly? Well, sure, you could do that, and in most cases it would be just fine.


A lookup table, just like macros in general, removes a layer of complexity from your code and replaces it with increased flexibility. Because you take away a transformation from the source (i.e. transliteration of the numerical month to the written month name), you are free to use the numerical month elsewhere in your computations.

Also, a lookup table is an indexing operation and not strictly a calculation, so the runtime processing power it requires is significantly reduced when compared to having your scripts do all the work. With a large setup, where lookup tables might go through a huge number of source and target operations, you’ll end up with less code, less computation, and a nice and flexible framework for value assignment in your macros.

To keep the operation as light as possible, you can only check for equation, e.g. “if {{target macro}} equals something, then…”. I actually asked Brian about this, and he replied:

Brian Kuhn on predicate evaluation

So if you want to see some other ways of evaluating the source value before assigning a target value, you’ll have to wait and see what the GTM team come up with. I guess it will be some combination of rule + lookup table to keep the setup as simple as possible.

Naturally, you can refer to your lookup table macros in Custom HTML tags and Custom JavaScript macros as well, so you’ll increase the modularity of your code.

Use cases

Let’s put it this way. Any time you need to do a simple “if X is Y then Z” evaluation based on a range of values, you could do so with a lookup table. Let’s start with a simple one.

Multi-account or multi-property container

If you have a single container deployed across many Google Analytics accounts or properties, you’ll come across the problem of assigning the correct tracking code to your tags. You could do it with a unique tag for each deployment, a unique rule for each tag, and a bunch of macros and custom HTML code to check the correct account, but that will soon turn into a veritable noodle-o-rama of a setup.

Relax. Use a lookup table:

Tracking Code Lookup Table example

Filetype defines event category

This is an example of using macros in the lookup table itself. I have a custom JavaScript macro, which checks the filetype of the link that was clicked. It uses the gtm.element auto-event variables used in auto-event tracking. See how I use a macro in the target value field? That’s how flexible this is. You can create a framework or infrastructure of macros, and come up with something really complex with very simple processing.

Be sure to follow the great Carmen Mardiros from Clear Clues to find out (hopefully soon) about applications of complex indexing logic using macro-based syntax.

Macro in lookup table

More auto-event madness

Another nice use case for auto-event tracking is to set your event parameters depending on what type of auto-event interaction took place. For example, if a link was clicked, I’d want my event action to be the URL of the clicked link. If any click occurred, I want my event action to be the tag type (i.e. DIV or IMG or SPAN etc.) of the clicked element. And if a form was submitted, I’d want my event action to be the ID of the form. Like so:

Lookup table with Auto-Event Variables

Then you can just use a single event tag to send your different auto-event hits, with a trigger rule like “{{event}} equals OR {{event}} equals gtm.linkClick OR {{event}} equals gtm.formSubmit”.


The lookup table macro is designed to help you actually create a logical infrastructure for your GTM deployment. It also increases flexibility, since you can cross-reference lookup macros in your tags and other macros. I’m a huge advocate of macros in general, because the less you hard-code into your custom tags the better.

There’s no limit to the number of rows in a lookup table (other than general GTM data set limitations). I know that there’s also an import feature on the roadmap, so you can import your own, pre-defined lookup tables into the system. Mapping classifications from one data set to another will be something that especially large GTM implementations will benefit from.

Finally, I couldn’t agree more with Eric Erlebacher:

Eric Erlebacher G+

The GTM dev team is on a roll right now, and I hope it doesn’t stop anytime soon.


  1. Les says

    Simo: I continue to enjoy your blog posts on GTM and the associated knowledge you are displaying.

    I had made a post on the GTM Community forum which Phil Pearce made an excellent suggestion towards a resolution:”You could use a GTM [exact match] lookup table using {{referral}} >> your referralGroup”. Hmmm.. So I did a quick search and found your blog post.

    I’d like your opinion on if what Phil is suggesting makes sense.

    Here is the text of my query: “I am attempting to track traffic for a high volume (+100 URLs) of referral traffic in GA. I have 3 main categories of URLs ( so 3 sets of +100 URLs). And need to do so every month. And, of course, the URL list will change over time. GA has limitations (segments & Custom Reports) that do not allow me to to accomplish what I want to. I am wondering if I could somehow do this with GTM. Any thoughts / ideas out there?”

    I have never used this macro before. That being said, I think that the possible uses are endless.


    • says

      Hi Les, and thanks!

      You could use a Lookup Table macro for this, but it’s a lot of manual work. You’d need {{referrer}} as the lookup macro, with all your URLs in the first column, and e.g. “urlGroupA”, “urlGroupB”, “urlGroupC” as the return values, depending on which group the URLs belong to. You can replace the manual labor with a utility such as iMacros, which automates these types of manual tasks in your browser.

      Or you could create a lookup macro of your own using Custom JavaScript:

      function() {
      var urlGroupA = [“”, “”…];
      var urlGroupB = [“”, “”…];
      var urlGroupC = [“”, “”…];
      if (urlGroupA.indexOf({{referrer}}) > -1) {
      return “urlGroupA”;
      if (urlGroupB.indexOf({{referrer}}) > -1) {
      return “urlGroupB”;
      if (urlGroupC.indexOf({{referrer}}) > -1) {
      return “urlGroupC”;

      Then you’d push this macro into a visit-scope custom dimension in your pageview tag. After that, you can use this custom dimension to filter or segment your data in GA.

      If the referrer doesn’t fit your groups, the macro returns an undefined, and no custom dim is sent.

      • Les says

        Thanks for this Simo. I did respond on the GTM Community Forum as Brian had weighed in also. Great input. Do you want to continue the discussion there?

        (Please add a subscribe feature to your blog comments – Jetpack or similar will do it ;-) )

      • Nastasia says

        Hi Simo,

        but returning the final value as you do here:

        return "urlGroupA";

        Aren’t you returning the string “urlGroupA” instead that the array of values?


      • says

        Hi Natasia,

        Yes, that’s precisely what I’m doing. If you check Les’ question and read my response in full, the point of the Custom JavaScript macro was to return the name of the URL “bucket” to which the referrer URL belongs to.


      • Nastasia says

        Hi Simo,

        sorry for my misunderstanding, I was taking part of your code as an example for another purpose.

        Thank you very much for your explanation

  2. Les says

    I keep on coming back to this post Simo. I also did a walkthrough of Magic Script. So, imagine a scenario where one could automatically pull an updated data set into a GTM LookUp table. The pieces of the puzzle are indeed there. This would transition us to a more dynamic state!

  3. says

    Ha ha man! This i REALLY awesome feature i dont believe how i didnt see it before.

    BTW its great that you are writing about the “hidden features” of GTM and not the obvious one.

    Keep writing!

  4. says

    So imagine being able to export/import Macros across containers/accounts. Even more, imagine a repository of commonly used macros….. :-)

      • says

        It will happen. I am sure of it. I actually dreamt about GTM Containers last night (How wrong is that?!?)

  5. Grzegorz Marczak says

    Hi Simo,

    Very helpful – post & blog equally. I was wondering if the lookup table macro works with an empty value for “equals” – any experience with that?
    I’m actualy trying to find a nice solution to have a cookie value work as a custom dimenssion in UA. It works fine when the cookie itself exists and its value is not empty. In other cases – the dimension does not get reported (no standard ’empty’ or ‘not set’ in UA).
    As there is no “default value” in GTM for 1st party cookie macros i am trying to find a workarount. There is a custom javascript of course, but still hoping to figure out something more ‘regular’.


    • says


      Yes, the Lookup Table can look for an empty value. But that empty value has to be an empty string, “”. If a cookie isn’t defined, it returns an undefined type, and the only way to account for this would be to have another macro which checks if cookie type is undefined, and then returns e.g. a string “undefined”, which is then used in your Lookup Table to represent the situations when the cookie wasn’t found.

      But Custom JavaScript is way easier. Then it’s just

      function() {
      return {{cookie macro}}?{{cookie macro}}:’undefined’;

      This returns the value of {{cookie macro}} if it’s found, and if it’s not, it returns the string ‘undefined’.

  6. says

    Hi Simo
    great stuff – I just had a question about double trackers and the first example, use of multi-property containers.

    If the default setting is a tracker across all sub-domains, eg
    but also wish to run into a different tracker so will have two trackers, I presume this solution doesn’t work and the UA number is replaced on www by the second one specified in the lookup? is there a way to have two trackers without doubling everything up?

    • says

      Hi Jon,

      Yes, it’s replaced if you use the same macro in your second tracker tag. I don’t think it’s possible to send multiple trackers with one tag, so you’ll have to have a second tag anyway. In this second tag, you can simply have the other tracker’s UA-number. Your first tag (and tracker) will use the Lookup table and push the first UA-number with the first tracker.

      So with two separate tags you’ll have two different trackers and you won’t have to worry about anything getting mixed up, as long as you don’t use the same Lookup macro for both, since the Lookup can set one UA-value to each hostname only.

      I’m not a pro on multi-tracker setups, but this seems pretty logical. Just remember to test and test first :)

  7. Katherine says

    Hi Simo,

    Thanks for this. I’ve been experimenting a lot with Tag Manager over the last couple weeks and no matter what I’m trying to do I keep getting led back to your blog so it’s been a super helpful knowledge base.

    I’m currently working on a lookup table similar to your post publish month one above but I just can’t seem to get the custom javascript macro right. Is there anyway chance I could see your custom java for the {{post_publish_date_month}} macro you mentioned above?

    No worries if not – thanks for a great resource!

    • says

      Hi Katherine,

      Actually, the post publish date was just an example, and I hadn’t written a proper macro for it (yep, my dirty tactics are now revealed) :)

      However, here are some ideas. In my blog, for example, post publish date is stored in the HTML5 <time> element, and it might look like this:

      <time class=​”entry-time” itemprop=​”datePublished” datetime=​”2014-07-30T09:​22:​41+00:​00″>​30/07/2014</time>

      To get the month from this, I’d need a Custom JavaScript macro which looks like this:

      function() {
      var pTime = document.getElementsByTagName(“time”)[0];
      if(pTime) {
      var d = new Date(pTime.getAttribute(“datetime”));
      return d.getMonth()+1;

      This returns the number of the month in the datetime attribute of the time tag.

      The point is, if your date is formatted correctly (check Date object), you can create a new Date object using the string on your post. How you get the string depends how the publish date is presented. Optimally, it’s in a uniquely identifiable DOM element, such as a TIME object or a DIV/SPAN with a unique ID. Then you use the getMonth() method of this new date object to get the month (January = 0 which is why I add 1 to the result in the return statement).

      That’s the gist of it, but if you want more info just drop me a line in e-mail with an example of the HTML code holding the publish date and I’ll format the function for you :) ​

  8. Adam says

    Can a lookup table be used to return more than one value from an array? For example, I have multiple checkboxes in a form and I want to be able to record all these at once. Currently, I have used your custom javascript macro to return the checkbox IDs and feed these into Google Analytics as an event. However, the IDs are long and complicated and will be nonsensical to the end user in Google Analytics. So I want to use a lookup table to turn these awful IDs into useful acronyms. So far, I have been able to use a lookup table to change a single ID into a single value e.g. A = X or B = Y. But where both A and B have been checked I can’t seem to return both X and Y. Instead all I’m getting is undefined…

    • says

      A Lookup Table is used for a simple index lookup. There’s no predicate logic involved, so it’s just if A then B type of calculations at the moment. What you want to achieve has to be done with a Custom JavaScript Macro.

      • Adam says

        Thanks for the reply. Would you be able to point me in the direction of any helpful resources?

        And also, just wanted to echo what everyone else has been saying and thanks so much for this blog. It has been extremely helpful.

      • says

        Hi Adam,

        Thanks! I don’t really have any resource to link to, since this is more a JavaScript thing than GTM. However, here’s an idea that you can then expand upon. First of all, when going through the checked boxes, push them into a new Array which is then returned to the tag which called the macro:

        {{checked values}}
        function() {
        var inputs = {{element}}.getElementsByTagName(“input”),
        checkeds = [];
        for(var i = 0;i < inputs.length;i++) {
        if(inputs[i].type===”checkbox” && inputs[i].checked) { checkeds.push(inputs[i].id); }
        return checkeds;

        Then in your tag you’d have something like

        var checkedArray = {{checked values}},
        caLength = checkedArray.length,
        newCheckedArray = [];
        if(caLength) {
        for(var i=0; i<caLength; i++) {
        switch(checkedArray[i]) {
        case “goo”:
        newCheckedArray[i] = “Better Goo”;
        case “foo”:
        newCheckedArray[i] = “Better Foo”;
        newCheckedArray[i] = checkedArray[i];
        // Do something with newCheckedArray

        So this code loops through the array of checked box IDs and rewrites them into newCheckedArray[]. If there’s no match, the original ID is retained in the correct index. Then you’ll just need to process this to send the stuff to GA.

        Perhaps this is what you were looking for?

  9. Petros says

    Hi Simo: Thanks for this. I am currently labeling events with an Element ID. To make my data in GA more meaningful, I thought I’d use this technique to rename my Element IDs. Easy enough.

    When does the lookup table macro fire? I am assuming on pages where I am tracking Events.

    Also, can I do this with one large lookup table? Or should I set a limit of how many lookup operations are performed?


    • says

      Hey Petros,

      Macros don’t “fire” in the sense we think of tags. Rather, macros are resolved (i.e. executed and return values are processed) the moment the tag which refers to the macro fires. So if you have a tag where you refer to the Lookup Table macro, the second the tag fires the lookup will be resolved. That’s why it’s important to have the tag fire AFTER the auto-event occurs, e.g. with {{event}} equals gtm.linkClick. Otherwise element ID will not be in the data layer by the time the Lookup Table Macro is resolved.

      And there’s no need to start splitting your lookup tables. The cost of the operation is really small, regardless of how large the table is.

  10. Petros says

    Thanks Simo. I get it. The Macro firing order makes sense (and I had actually thought of that already!).

    Add-on Question: So if my Event Label currently says this: {{element id}} — {{element url}} at the moment….. As soon as I fire my Lookup Table Macro, {{element id}} will be replaced by whatever value I have in place for that particular lookup? It’s that simple?

    • says

      You need to use the {{Lookup Macro}} – {{element url}} in the Event Label. That way when the tag fires, the Lookup Macro is executed, where {{element id}} is evaluated. The string that the Lookup Table returns depending on the {{element id}} is the one that ends up on the tag.

  11. Stef says

    Really usefull article. I really like the idea of using one container in combination with a lookup table to fire different GA properties to different domains. The only thing is how can I check if each of my domains contain the right UA code? Normally I would use screaming frog to scrape html for a UA code but with GTM it’s not possible. Is there an other solution to check all/multiple pages if they contain the right UA code?

    And in a lookup table. Will also match or

    • says

      First of all, lookup table is exact match only. will only match

      As for the UA code thing, I don’t really see the relevance? GTM sends every single hit from a given domain to a given property, I don’t see how on-page code would affect this? As long as GTM container is on a page, all hits to that page will be sent to the correct property ID, depending on what domain the page in question is on.

      • Stef says

        Thanks for your answer. Will expend the lookup table with www non www variations. Regarding the UA analytics code, maybe my question wasn’t clear. What I mean is how can I check if the Analytics tag is implemented on all pages by GTM. Cause in the source code of the website you’ll only see the GTM tag instead of UA-XXXX. I know WASP crawl can do it limited (100 pages), is there an other way to check it easily

  12. Andrzej says

    Hi Simo!

    First of all – thank you for the great job with explaining all the GTM tricks so clearly. I’m no programmer and yet thank to your posts I was able to do much better work, than I used to. :)

    I used to use one of your LookUp Table macros (sending data to different Google Analytics properties) and it worked perfectly, but now I have one problem. The set up for both scenarios looked like this:

    1. Creating one property (i.e. UA-XXX-1) for standard traffic
    2. Creating another one (i.e. UA-XXX-2) for my GTM tests
    3. Creating “ifDebug” macro – returning true/false for debug mode in GTM
    4. Creating LookUp Table “UA property”: If “ifDebug” equals to: true – than “UA property” is UA-XXX-2; and if it’s false then set it up to UA-XXX-1
    5. Creating UA pageview tag (firing rule: all pages) which sends data to: {{UA Property}}.

    And for my previous implementation that worked like a charm. Now, however, it does not. Standard traffic goes smoothly to property ending with 1. But the traffic supposed to be sent to property nr 2 goes nowhere…

    The only difference betweend those two implementation is the old one was set with old GA code, and the new one with Universal Analitycs.

    I am debugging and viewing the right version of the container (all tags, rules and macros verified). I’ve checked the value of the pageview tag with the GTM debug console and it is correct (property nr 2). But no data shows up in the “live” reports. Do you have any suggestions, what else should I check?

    Best Regards,

    • says

      Are you SURE that your test property is Universal Analytics? If it’s in legacy GA you won’t get hits as you can’t send UA hits to the classic account.

      Other than that, if the tag is firing, and if you see requests to /collect endpoint using a Network debugger or WASP, for example, I have no other suggestion than to check your filters etc. in your GA profile to make sure they’re not filtering out the traffic.

      • Andrzej says

        Yes, it is an Uviersal Analytics Property. And I’ve checked within the WASP the /collect endpoint. Proper values everywhere (standard traffic: UA-XXX-1, with debug mode: UA-XXX-2). Right now no filters are applied. It’s quite new instalation. First I wanted to check if everything is OK with testing environment, and clearly it’s not… But thanks for your time. I think I’ll start from scratch.. ;)

  13. says

    Please help Simo, how can i create a new Google Analytics Channel for the Google Image Search? I See lots of these referrer google/imgres :( Thank you

  14. 1234abc says

    Am i right? A lookuptable with with regex like “url equals .*test.*” is not possible. how do you solve a search for multiple words or charaters in a url? i think it would be nice to use a table for this instead of a endless list of .*test1.*|.*blabla2.*|.*test3.* is it possible to return all values of a search tabel with javascript as an array or something similar?

  15. Mark says

    Thanks for your post Simo you have the best content for Google Tag Manager out there.

    I actually referenced another post you had on advanced form tracking and was able to use the below script to capture the drop down list item submitted. The developer uses a numeric number to reference the item selected: example: 311 = Pet Services.

    The Event label showing in Google Analytics is 311 but I want it to show Pet Services instead. When I create a macro lookup table to redefine the values pushed to GA it doesn’t work. Any thoughts? Thanks for your blog!!!!!!!

    function() {
    var selectId = “edit-categories”;
    try {
    var options = document.getElementById(selectId).options;
    for (var i = 0;i < options.length;i++){
    if(options[i].selected) {
    return options[i].value;
    } catch(e) {}
    return "";


Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not write HTML or other formatted code in your comments!