Leverage Enhanced Ecommerce Data Layer for Marketing Pixels

This post contains scripts that you can use as Custom JS Variables in Google Tag Manager. These scripts all target the quite specific (yet common) use case where a site already running Google Analytics Enhanced Ecommerce now needs to run additional marketing or analytics tags.

CONTENTS

Background
Prerequisite: Create a Data Layer Variable for the Products Array
Script 1: Total Quantity
Script 2: Total Price
Script 3: Subset of Product Attributes
Script 4: Comma-Separated List of SKUs
Script 5: Array of SKUs
Final Step: Add Custom JS Variables into a Custom HTML Tag

BACKGROUND

Most marketing and analytics tools come with their own tracking pixel (aka script or tag). These pixels usually look something like this, where you are expected to fill in dynamic values for 'total_quantity', 'total_price', and 'products':

<script type="text/javascript " charset="UTF 8" src ="//t1.sitecdn./static/kp.js"></script>
<script type="text/javascript">    
    marketingPixel('123456789').pageView();
    marketingPixel('123456789').purchase();
        total_quantity: "2",
        total_price: "300",
        products: [
         { name: "snack1", quantity: "1", price: "200"},
         { name: "snack2", quantity: "1", price: "100"}
       ]
});
</script>

If you are using Enhanced Ecommerce for Google Analytics on your site, most likely your developers have already created a data layer for Google Tag Manager (GTM) that contains all the raw information you need to populate the above tag. This is a standard Enhanced Ecommerce data layer that would be active on a 'transaction complete' page:

window.dataLayer = window.dataLayer || [];
dataLayer.push({
  'event': 'purchase',
  'ecommerce': {
    'purchase': {
      'actionField': {
        'id': 'T12345',                         
        'affiliation': 'Online Site',
        'revenue': '35.43',                     
        'tax':'4.90',
        'shipping': '5.99',
        'coupon': 'SUMMERTIME_SALE'
      },
      'products': [{                            
        'name': 'Hammer Pants',    
        'id': '12345',
        'price': '15.25',
        'brand': 'Jamz',
        'category': 'Clothing',
        'variant': 'Blue',
        'quantity': 1,
        'coupon': ''                            
       },
       {
        'name': 'Original Board Shorts',
        'id': '67890',
        'price': '33.75',
        'brand': 'Jamz',
        'category': 'Clothing',
        'variant': 'Red',
        'quantity': 1
       }]
    }
  }
});

It contains information about transaction IDs, revenue, product quantities, prices, and so on, which, unsurprisingly, is the same information required by many marketing and analytics tags. This post will provide instructions and scripts to leverage and reconfigure a GTM Enhanced Ecommerce data layer to satisfy some commonly requested patterns.

PREREQUISITE: CREATE A DATA LAYER VARIABLE FOR THE PRODUCTS ARRAY

Before we move forward, create a data layer variable pointing to the entire products array. We'll reference this value in the scripts below.

To do this, in GTM navigate to Variables > New > Data Layer Variable, and set Data Layer Variable Name to ecommerce.purchase.products.
ee-datalayer-other-pixels-img1

You can name it whatever you like, but for this example we'll name this variable DL - ecommerce.purchase.products. (It will be easier to follow along if you use the same names.)

SCRIPT 1: TOTAL QUANTITY

This script will return the sum of all quantities in the products array. We'll name it 'JS - Total Quantity'.

function (){    
var prods = {{DL - ecommerce.purchase.products}};  
var i;
var sum = 0;   
if (!prods) { return; }
   for (i = 0; i < prods.length; i++) {    
    sum +=parseInt((prods[i].quantity))
}   
return sum; 
}

SCRIPT 2: TOTAL PRICE

The following script will return the sum of all prices in the products array. We'll name it 'JS - Total Price'.

function (){    
var prods = {{DL - ecommerce.purchase.products}};  
var i;
var sum = 0;   
if (!prods) { return; }
   for (i = 0; i < prods.length; i++) {    
    sum +=parseFloat(prods[i].price*prods[i].quantity)  
}   
return sum; 
}

SCRIPT 3: SUBSET OF PRODUCT ATTRIBUTES

This script will let you extract certain product attributes from the Enhanced Ecommerce data layer. Let's call it 'JS - Product Attributes'.

function() {
  if (!{{DL - ecommerce.purchase.products}}) return;
  
  return {{DL - ecommerce.purchase.products}}.map(function(product) {
    return {
     name: product.name,
     quantity: product.quantity,
     price: product.price
      }   
     });
}

The above script will produce a new array of products, containing just the name, quantity, and price attributes, like this: [{ name: "snack1", quantity: "1", price: "200"}, { name: "snack2", quantity: "1", price: "100"}]

Variation 1: If you need different attributes, you'd need to modify the above script slightly. For example, if you needed to include the product category, you'd add 'category: product.category' after 'price: product.price'.

Variation 2: If your tag requires that you rename the attribute to something else, you'd again modify the script. For example, if they need to receive the price in a key named 'value' instead of 'price', you'd change 'price: product.price' to 'value: product.price'.

SCRIPT 4: COMMA-SEPARATED LIST OF SKUS

This custom JS variable will produce a comma-separated list of purchased SKUs (e.g. "50460492,50949783,51386761").

function(){  
  var prods = {{DL - ecommerce.purchase.products}};
  var skus = [];
  var i; 
  if (!prods) { return; } 
  for (i = 0; i < prods.length; i++) {
    if (prods[i].id) { skus.push(prods[i].id); } 
  } 
  return skus.join(',');
 }

Variation: If you need a different delimiter, e.g. a pipe instead of a comma, just replace the character located inside the return skus.join(','); snippet.

SCRIPT 5: ARRAY OF SKUS

This custom JS variable is almost the same as the above, but will return the list of SKUs as an array (e.g. ["50460492", "50949783", "51386761"]) instead of a string. Some pixels require this format, e.g. the Facebook Dynamic Ads pixels.

function(){  
  var prods = {{DL - ecommerce.purchase.products}};
  var skus = [];
  var i; 
  if (!prods) { return; } 
  for (i = 0; i < prods.length; i++) {
    if (prods[i].id) { skus.push(prods[i].id); } 
  } 
  return skus;
}

ADD CUSTOM JS VARIABLES INTO A CUSTOM HTML TAG

Once you've created custom JS variables containing the values you need, in the correct format, substitute them into a new custom HTML tag. For example, returning to the example tag requirements at the top, you'd create a tag like this:

<script type="text/javascript " charset="UTF 8" src ="//t1.sitecdn./static/kp.js"></script>
<script type="text/javascript">    
    marketingPixel('123456789').pageView();
    marketingPixel('123456789').purchase();
        total_quantity: {{JS - Total Quantity}},
        total_price: {{JS - Total Price}},
        products:  {{JS - Product Attributes}}
});
</script>

Set this tag to fire on the transaction page, and it will send the correct, dynamically populated tag to your marketing vendor.

20 thoughts on “Leverage Enhanced Ecommerce Data Layer for Marketing Pixels”

  1. Hi Ana! Thanks a lot for this great article, I have been looking for those JS utilities lately and again found the answer at your blog;) Regarding the external pixels are now covered, but how about enhancing the eCommerce data layer to send extra parameters to GA (for dynamic remarketing) ? Is it always a modification of the code needed (so it populates as well: (for retail (for instance)) ecomm_prodid, ecomm_pagetype, ecomm_totalvalue to data layer directly? Or you could think of a JS that would convert the enhanced ecommerce data from the standard implementation into the format that would match custom dimensions in GA. Just like Patrick Strickler did for Client, Session, Hit IDs in one of his articles. Please check the article attached. Not sure if this a good idea, just struggling with it this days...

    • Hey Anton, thanks for the comment! For dynamic remarketing you can use the data layer values that are already there: 'id' and 'revenue' for 'ecomm_prodid' and 'ecomm_totalvalue'. You'd extract those values into GTM with custom JS variables and/or DL variables and attach them to your dynamic remarketing tag. Page type isn't part of the default EE data layer, though, so you'd need to push that in separately, like this:

      window.dataLayer = window.dataLayer || [];
      dataLayer.push({
        'event' : 'pageview',
        'pageType' : 'checkout'
      });
      

      If you wanted you could bundle in 'pageType' as part of your EE data layer push, but I usually see it pushed separately.
      I'm not totally sure what you mean by 'JS that would convert the enhanced ecommerce data from the standard implementation into the format that would match custom dimensions in GA', can you please clarify what you're looking for?

  2. Hi Ana, great great tips... I tried use your subset product var but it doesn´t works. Then i try modify the SKU script to create a subset products but it doesn´t works too. Do you know why this script it doesn´t works based in your scripts??
    function(){
    var prods = {{DL - Ecommerce}}.purchase.products;
    var name = [];
    var price = [];
    var quantity = [];
    var i;
    if (!prods) { return; }
    for (i = 0; i < prods.length; i++) {
    if (prods[i].id) { name.push(prods[i].id),price.push(prods[i].id),quantity.push(prods[i].id); }
    }
    return prods.join('|');
    }

    • Hey Lolo, can you please double-check that you're using the Enhanced Ecommerce (not Standard Ecommerce) data layer on your site? If the data layer doesn't exactly match the Enhanced Ecommerce syntax, the rest of the scripts won't work either. But if it does match, there shouldn't be any issue.

      To trouble-shoot, I suggest turning on GTM preview mode, making a test transaction, and checking what value gets passed into your {{DL - Ecommerce}} value. You can also type the word 'dataLayer' into your dev tools console to see the entire ecommerce data layer.

      • hi!! i set the EEC in GA and i´m using GTM4WP, in a woocommerce site. I can´t see values in the DL Var into data layer. I don´t know if the script is correct (i don´t know a lot about programming). In other cases using your original scripts (array sku) i get the values into RT report of GA. With other scripts of this post, i get values into GTM preview mode, (with [ ]) but not in RT report of GA

      • I don't really know anything about how GTM4WP creates a data layer. However, since the Array of SKUs script works, it implies they're using the Enhanced Ecommerce data layer, so it seems like everything else should work as well. The Array of SKUs script creates an array, while some of the other scripts create strings and numbers, so maybe your report requires an array (I don't know what the RT report is).

        Your script above seems like you're trying to populate several different arrays at the same time, but you're sending the same value (prods[i].id) into each one of them and then not returning any of those arrays anyway. What is the final output you're looking for?

  3. RT means Real Time Report in Google Analytics, sorry 🙂
    My last intent:
    JS-Productos Ecommerce:
    function(){
    var prods = {{DL - Ecommerce}}.purchase.products;
    var name = [];
    var price = [];
    var quantity = [];
    var i;
    if (!prods) { return; }
    for (i = 0; i < prods.length; i++) {
    if (prods[i].id) { name.push(prods[i].name);price.push(prods[i].price);quantity.push(prods[i].quantity); }
    }
    return prods.join('|');
    }

    I get this value into this JS var:
    '[object Object]'
    Maybe the script is not writed correctly?
    Thanks a lot for your support. Is great!!

    • Hey, I'm not totally sure what you want the output to look like, but this doesn't look correct to me.
      Your script looks like it does this:
      1) sets the var 'prods' as the products object.
      2) defines 3 new variables: name, price, and quantity.
      3) pushes all the product names into the name variable, the prices into the price variable, and the quantities into the quantity variable
      4) returns the prods var, which is still the same object you started with.

      If you're trying to return multiple variables, I suggest checking the 'subset of product attributes' script. But it really depends on what you're looking to get at the end.

      • Thanks for your comments. The topic is with your subset script i collect the next values:
        [
        {name: 'Camiseta cascuda', quantity: 1, price: 52},
        {name: 'Hoodie con bolsillo canguro', quantity: 1, price: 75}
        ]
        but in Google Analytics with this label tag event:
        "Compra Finalizada: Total: {{JS - Total Price}} € | Subset Atributos: {{JS-Subset Atributos}}"
        i get this in Google Analytics Real Time Report:
        "Compra Finalizada: Total: 128 € | Subset Atributos: {{[object Object], [object Object]}}
        For this reason i tried by other of your scripts 🙁

      • OK, I finally understand what you're trying to do :p
        The output of the subset of product attributes script is a JSON object, which can't be displayed in Google Analytics event fields. These scripts were designed for marketing pixels, not for GA.
        If you want to pass values into GA, you need to make sure those values are strings, not objects. The easiest way is probably to just make a new custom JS variable like this:

        function(){
         return JSON.stringify({{JS – Product Attributes}});
        }

        That will return your product attributes object as a string, so you can then add this new variable into your event tag.

  4. Hi, GREAT SUPPORT!! Now i understand. Then, you means that to collect in GA the data i want in a subset, i have to create a CJS var, and paste the next inside:
    function(){
    return JSON.stringify({{JS – Product Attributes}});
    }
    isn´t it?
    The next question is if you have any course than show how work with GMT-EEC-Ads Pixels (Facebook&Google Ads). I´m very interested in your way of teach. This post help me a lot!! And your support much more!! 🙂

    • How can i delete the next simbols in Attributtes names e.g "categoria"-"producto"- "precio" - "cantidad":
      " , { , and [
      and how can i separate products with "|" symbol in the collected string with your function:
      Subset Atributos: [{"categoria":"Sweaters","producto":"Hoodie con bolsillo canguro","precio":75,"cantidad":1,"talla":"xl"},{"categoria":"Cap","producto":"Gorra de pana orgánica y PIÑATEX","precio":53,"cantidad":1}]

      to get something like this:

      Subset Atributos: [categoria:"Sweaters", producto:"Hoodie con bolsillo canguro", precio:75, cantidad:1, talla:"xl" | categoria:"Cap", producto:"Gorra de pana orgánica y PIÑATEX", precio:53, cantidad:1]

      • I think the replace method probably does what you want. For example, this would remove all the quotation marks:

        function(){
         return JSON.stringify({{JS – Product Attributes}}).replace(/"/g,"");
        }

        This is just a JavaScript question, so you can check out some JS tutorials online and then change your output exactly the way you want.

  5. Thanks for this - awesome reference!

    I'm struggling with the "total price" script. When using the updated Google ecommerce framework (https://developers.google.com/tag-manager/ecommerce-appweb) which uses the term "items" in place of "products", the DLV keep showing as "undefined" when using this script:

    function (){
    var prods = {{ecommerce.items}};
    var i;
    var sum = 0;
    if (!prods) { return; }
    for (i = 0; i < prods.length; i++) {
    sum +=parseFloat(prods[i].price*prods[i].quantity)
    }
    return sum;
    }

    Any advice?

    • Hi John! I checked out the new data layer format and the “price” and “quantity” fields haven’t changed from the GTM format. So I’m not yet sure what the issue is, since it looks like it should work. Just to confirm, you changed the DL variable from ecommerce.purchase.products to ecommerce.items, right? And, do the other scripts from the post work? If so, can you please check if your data layer is using a non-standard format or missing the price/quantity fields in the items array?a

  6. Hi there! Thanks for this article.

    How would I filter our a specific product ID from the ecommerce datalayer and count the quantity for all other products?

    e.g. if product id = 1001 exclude from count of product quantity?

    Thanks!

    • I think you'd just need to add in a second conditional statement to exclude the product ID. Something like this should work:
      function(){
      var prods = {{DL - ecommerce.purchase.products}};
      var i;
      var sum = 0;
      if (!prods) { return; }
      for (i = 0; i < prods.length; i++) { if (prods[i].id!="1001") {
      sum +=(prods[i].quantity)
      } }
      return sum;
      }

  7. Hi there,

    I've tried the first script (total quanity) and have implemented the following Custom JS:

    function (){
    var prods = {{DL – ecommerce.purchase.products}};
    var i;
    var sum = 0;
    if (!prods) { return; }
    for (i = 0; i < prods.length; i++) { sum +=(prods[i].quantity) } return sum; }

    However, it doesnt really sum, but it concatenates as a string to '011', while my endresult should be '2' (quantity 1+1)

    Data Layer Variable array
    [
    {
    id: '1',
    name: 'Test product 1',
    price: '4.54',
    quantity: '1'
    },
    {
    id: '2',
    name: 'Test product 2',
    price: '20.25',
    quantity: '1'
    }
    ]

    How can I change this? Thanks for your help!

    • In JS, the plus operator will concatenate instead of add values if at least one is a string. Since your quantity (and price) have quotation marks around them, they are strings instead of numbers, so that's causing this issue.
      Anyway, you can resolve this either by making sure your quantities are passed in as numbers to start, or by adjusting the script to force any number-like strings to numbers. Something like this should work:
      function (){
      var prods = {{DL – ecommerce.purchase.products}};
      var i;
      var sum = 0;
      if (!prods) { return; }
      for (i = 0; i < prods.length; i++) { sum +=parseInt((prods[i].quantity)) } return sum; }

Comments are closed.