App + Web Ecommerce Tracking Part 1: Pre-Checkout Eventing

by Rob English

My attempt at deploying my App + Web Ecommerce tags using the Universal Analytics dataLayer

Earlier this year, Google gave us our first look at the new dataLayer schema for Ecommerce handling, in App + Web.  When first launched, after reading the documentation, there was something that stood out as a little concerning for me.  

As App + Web (A+W) is very much a Beta and shouldn’t be a standalone deployment, general consensus is to run it alongside your Google Universal Analytics (GUA) deployment.  For App + Web, the ecommerce dataLayer schema differs just enough from our Universal Analytics ecommerce dataLayer schema, that it requires us to duplicate most of our ecommerce data, in our dataLayer, in both the products array 

 GUA recognizes, and the new items array that A+W recognizes.  For example:

Typically, I don’t like to introduce redundancies like this into my data layer, where we’re capturing the exact same piece of data across two keys.  I always recommend consolidating into a single key where possible.  It’s cleaner, there’s less confusion, and there’s less risk of introducing inconsistencies into these similar keys somewhere down the line.

In late August, while reading up on the release of Ecommerce reporting for App + Web, I was also pleasantly surprised to find out that backwards compatibility between the App + Web and Universal Analytics ecommerce object had also been introduced at some point during Spring or Summer of 2020.  No need to duplicate the products array, after all!

As soon as I heard this I was curious to see how this would be done, so I jumped over to the Google Developers page, for GTM to get more info.

Unfortunately, there weren’t a lot of specifics on how to use this backward compatibility feature, but once you get into the tagging side, it does become clearer.  Having walked through it, I thought I’d share my findings, on Dual Deploying to my own test site, the workflow I went through, and some of the limitations I faced.

The approach I’m taking to my implementation is ABSOLUTELY NO REWORK to my existing dataLayer at all, so I’m treating this as strictly a GTM project, following what was mentioned in the Google Tag Manager docs of replacing ‘items’ with ‘products’ or ‘impressions’.

A few things to keep mind:

  • This article assumes that you already have a basic App + Web deployment via GTM.  What we’re doing here builds off of an already existing App + Web configuration tag.
  • The way I’ve structured these examples is one tag per one e-commerce event, to give a clearer understanding of how these values need to be set up on an event by event basis. 
  • I’ll only be focusing on “pre-purchase” and “pre-checkout” related events, as all of these events use the same logic to dual deploy.  Purchase and Checkout are a little more involved, so I’m going to focus on them in later posts.  We’ll start simple, and work up to the more complicated stuff later.

Ecommerce object mapping

Before we jump into the tag configuration side of things, we’ll want to clearly define some values that will be relevant to our new tagging.  The below table outlines:

  1. The Ecommerce event to which we’re referring, as we’ve come to be familiar with them in GUA.
  2. The A+W Ecommerce event name.  This will be the value we need to map to our A+W ‘Event Name’ parameter in order for A+W to translate each into its associated e-commerce event.
  3. The Product array mapping.  This refers to where the product (or promo) data for each event should currently reside in your GUA dataLayer schema.
  4. And finally, the Item array mapping, where our product data will be mapped to in our A+W tagging.

Step 1 – Create our ecommerce.impressions Data Layer Variable

Because our Universal Analytics tags pick up the ecommerce.impressions array automatically, I don’t have a Data Layer Variable set up specifically to collect this data just yet.  In this case, this is where I need to start (if you already have it, feel free to skip ahead).

In GTM, go to our Variables tab > User-Defined Variables > New

Name this variable Data Layer – ecommerce.impressions

In the Variable Configuration section > open the Variable Type panel > Data Layer Variable 

Next, in the Data Layer Variable Name field I’ll enter ecommerce.impressions

You should now have a Variable that looks like this.

Click Save.  

If we enable GTM preview and jump over to our website, to a page where  impression data exists, and go to our Variables tab, we should see our impression data being set in this new variable.

Step 2 – Create our App + Web impressions event tag

This assumes you’ve already created the necessary App + Web Config tag.  If you don’t have a config tag, I recommend you do this before you continue any further.

Go to Tags > New

Let’s name our tag: A+W – impressions event tag

In the Tag Configuration section > open up the Tag Type panel > Google Analytics: App + Web Event

The first thing we need to set up on our event tag is our Configuration Tag.  Under the Configuration Tag drop-down, we’ll select our already existing A+W – Config tag

Step 3 – Define our Impressions Event Name, and assign Event Parameters

This is where the table mentioned above, under our Ecommerce Object Mapping section will come in to play.

In our A+W – Impressions event tag, under Event Name, we need to tell Google Analytics what the specific ecommerce event this tag is for.  With A+W we can assign any value we like to this variable for most, (but not all) eventing.  For specific events, like ecommerce events, this value has to exactly match the values defined by Google.  For impression tracking, we need to define this as: view_item_list

To get a better idea of what all of these defined event names and events are, check out Google’s documentation here:

Next, let’s open up the Event Parameters tab on our tag > Click ‘Add Row’

In our Parameter Name field, we’ll enter items.  This is the defined parameter for sending e-commerce product (item) data to App + Web reporting, so it’s very important that for any e-commerce event tag when you map your product data, you’re mapping it to the items parameter.

On the Value field, enter our recently created {{Data Layer – ecommerce.impressions}} variable. 

Step 4 – Bind the same trigger you’re using for your GUA impression event, to our A+W tag

Let’s scroll down to our Triggering section, click to Add a Trigger, and select the exact same trigger you’re using for your GUA impression tracking.  In my case, that trigger is Custom Event – ecommerce – impressions

That’s it!  

Our impression tag should now look like this:

We now have our first dual deploy instance of a GUA / A+W ecommerce event created.  The above logic applies to all of your event driven GUA Enhanced Ecommerce events.  You’ll need to:

  1. Create a Data Layer variable that will collect the products array for each of your ecommerce events, (note that for impressions it’s the impressions array, promo events it’s the promotions array, and all other product related events products array).
  2. Create an A+W equivalent event tag for the Ecommerce event.
  3. Define the Event Name as the predefined Ecommerce Event Name set out by Google.
  4. Map the variable we created in Step 1, to an Event parameter called items (this is consistent for ALL of your Ecommerce events in A+W)
  5. And finally, bind the same trigger you’re using to fire the GUA equivalent of this ecommerce tag, to the new A+W tag.

If we enable GTM preview now, jump over to our site, and trigger an impression event, we should see a GUA collect hit get sent out, and then an A+W collect hit get sent out.

Note the format of our product data on A+W event hits.  We no longer have the individual product parameters listed out line-by-line as we do with GUA, but rather a nested pr[n] parameter collecting all of our item params, per item.

I don’t send my Impression data with a Custom Event, but rather with my Page View hit, what do I do?

This is one of the differences in how we have to address our Ecommerce events between A+W and what we used to do with GUA.  When we think of how GUA handles Page View and Event tracking, each is its own separate hit type, their hierarchy looks something like this:

Page View

  • Ecommerce Action (product action parameter you’ll see in collect hits)
    • Product data


  • Event details (Category, Action, Label)
  • Ecommerce Action (product action parameter you’ll see in collect hits)
    • Product data

Because of this, it’s very possible to send Ecommerce data with our page view hits.  In fact, I recommend it where possible (though that may change in future GUA deployments, in anticipation of A+W support), and it’s how Google’s documentation shows handling dataLayer.push calls for ecommerce data that is most likely sent with a page view (think impressions, details, checkout, and purchase data). 

With App + Web, page views are no longer their own tag type

.  Instead, they’re an event just like everything else, as are Ecommerce events. They all require sending a unique Event Name in order to determine: “this is a page view” or “this is a login event” or  “this is a product impression”.  No longer will we be able to define “this is a page view with impression data”.  The new hierarchy looks very much like this:


  • Event name = page_view – Defines the event as a page view event
    • Item data – This doesn’t work.


  • Event name = view_item_list (impressions) – Assigns the Ecommerce event the data applies to for Ecommerce reporting
    • Item data

If you’re sending e-commerce data to your dataLayer for the Page View, and not with its own event, no problem.  We can account for that in GTM as well.  The easiest way to do this is to create a Custom JS variable that will determine whether impression data exists in our dataLayer or not, at page load, and fire our impression tag accordingly.

Step 1 – Create a Custom JS variable to validate whether impression data is present in the dataLayer or not

Let’s go to the Variables tab in GTM > under User-Defined Variables > New

We’ll name our variable, Custom JS – Validate ecommerce.impressions object, and we’ll then click into the Variable Type pane > Select Custom JavaScript.

Now, in the Custom JavaScript text field, we’ll enter:

function() {

  if({{Data Layer – ecommerce.impressions}}) {

if({{Data Layer – ecommerce.impressions}}.length > 0) {

     return true;



    return false;


This script will check for the existence of our e-commerce.impressions array, and, if it has a length (so as long as it’s not just an empty array []), it will return true, otherwise, if it doesn’t exist, returns false.

The above is a very simple script that will check to ensure the key exists, and that it contains a value.  It won’t differentiate that value from the expected array of objects or a string, so you still need to make sure you’ve configured your impression data properly in your dataLayer to meet the expected standards – which, if your GUA impression tracking is working right, should be fine… otherwise, this could still evaluate true if you’ve defined something like ‘impressions’ : ‘yes’, and you can end up passing an impression event without any impressions attached to it.

Before we move on, let’s quickly jump over to our website, to make sure this variable works as expected.

First, lets go to a page that contains impressions, and we should see something similar to this:

The above shows our validate ecommerce.impression script is validating as true.  Our ecommerce.impressions variable returns impressions from our dataLayer.

Now, let’s go to a page where you aren’t going to have any impression data present. You should see something like this:

When our ecommerce.impressions variable returns undefined, our validate ecommerce.impressions script is evaluating as false. This means we shouldn’t have to worry about this event firing on pages where impressions aren’t a thing.

Step 2 – Create a new trigger Page View trigger

Next up, we’ll need to create a new trigger to fire at Page Load, only on pages with Impression data (so when our Custom JS variable evaluates as true).

Click in to Triggers > New

We’ll name our Trigger Page View – Impressions exist

Click into the Trigger type pane > select Page View as our Trigger type

Now, under ‘This trigger fires on’, we’ll specify:

Custom JS – Validate ecommerce.impressions object equals true

What this Trigger is now saying is:

“On Pageview,  If the Impressions object validates as true (ecommerce.impressions found on page)”, fire any tag this Trigger is bound to.”

And finally, bind the trigger to our newly created A+W – Event – Impressions tag

If you currently send impressions both at and after page load, it’s perfectly fine to create both sets of triggers mentioned in this guide, and bind them to your Impressions tag.

Now, if we Refresh GTM Preview, and visit a page on our website where Impression data exists at page load, we can see in the GTM Preview pane that our tag is fired. 

Jumping over to our Network tab, we can then see that the Collect hit is sent out, with our Impression data attached to it. 

You may notice in my screenshot that my event data looks slightly different from previous A+W collect hits I’ve shown in this article.  There’s a new ‘Request Payload’ section, and within that, separate lines, each containing a different Event Name (en) parameter: one for page_view, one for view_item_list and one for scroll.

This is normal, it’s just instances of multiple A+W collect hits being batched into a single request. 

If you need to apply this Page load logic to other ecommerce events, the workflow is the same, in that we’ll need to:

  1. Create a ‘Custom JS – Validate ecommerce.[ecommerce event].products’ (or… ecommerce.promoView.promotions) variable that will evaluate true or false.
  2. Create a unique trigger for this particular Page Load event, ensuring to include the condition, that the variable created in Step 1, evaluates to true
  3. Bind the newly created trigger, to our A+W Ecommerce event tag.

If you have dev resources available who can update your dataLayer directly to split up the e-commerce data from your page load into separate dataLayer.push instances, I’d tend to lean towards that method, and then modify your tags to meet that structure accordingly.

Checking our Data

Now that we’ve got all of our tags set up, I want to make sure it’s tracking as expected, so I’ll jump over to Google Analytics and have a look at the actual data being received.  Like with GUA, it can take some time for your data to show up in your Reporting property, around 24 hours.

Prior to the below reporting examples I triggered a series of Ecommerce events for Impressions, Product Click, Product Detail, and Add to Cart so that we’d have a full set of Pre-Checkout data we could view.  My impressions included the list name “My New List”.
If we visit the Ecommerce tab in our A+W property, the two dashboards/reports we’ll be working with are Ecommerce purchases by item name, and Ecommerce purchases by item list name.  They’ll still show as empty right now, as I haven’t implemented my purchase event, but if we click into them to get their full reports, we’ll be able to see the events that would lead up to a purchase.

The first one I’m going to have a look at, will be my Ecommerce purchases by item name report.  Clicking in to it, we’ll be able to get details on some of the other ecommerce events that would normally lead up to that purchase, like Item views and Add-to-carts.  And so far so good, I can see my product data showing up, and being set for those events. 

Next up, if we go back out to our Ecommerce home page, let’s have a look at Ecommerce purchases by item list name.  This will take us to an A+W equivalent of our GUA Product List Performance report.  

Clicking into the purchase by list name report, I then scroll down to the bottom of the new report page, and I can see the breakdown of my “Product List Performance”. 

As seen in the below screen cap, my Impressions event works!  It’s showing up as expected.  I only viewed the list once, so we have our one item list views impression populating.

BUT, notice that I have no item-list-clicks or Add-to-carts tracking for this list, despite having just said I triggered all of those events on this list.

Instead, these events appear to be bucketed under the (not set) list.  This isn’t good. But, it’s as expected when deploying against my GUA dataLayer schema because I’ve taken advantage of the attribution that can be done on Product List tracking in my GUA dataLayer/tagging.  I had a feeling this was going to happen for my A+W deployment.

So… why is this happening, and can we fix it?  

This is related to a GUA feature, that has been referred to as Product List ‘Attribution’.  With our GUA deployments, we could set our product list in two places: With our Impressions, and then again in an actionField.list variable on the product click.  From there on out, provided the product id has remained the same through the detail, add, checkout, etc., and provided we don’t overwrite the list value set in actionField.list at some point, it would attribute all of  these future ecommerce actions on that product (within the session), to the list set in that actionField.list property on our click.  This was a really awesome feature, as it meant only setting the list value on the ecommerce events within our product listing pages, vs. across numerous page types, ecommerce events etc, making for trickier onsite development to support.

That… is a really quick, overview of what is happening, but Simo Ahava has a great article that I highly recommend reading. It goes much deeper into detail on what this is, and how it works:

So… now the question is, can we fix it?  We can, but, as the goal of this article is to focus on a dual deploy with no dataLayer updates or manipulation to see what happens, I won’t focus on it here… it basically leads into its own lengthy followup, and I didn’t want to lose focus on the original purpose of this particular post.  It’s definitely something I’m going to keep exploring and hopefully can follow up with here soon.

For now, in my build, I’m just going to leave as is.  I’m able to report on my product data fine from what I’m seeing, I’ll have some Product List issues to work on later.

If I return to my reporting.  I want to see how my product tracking is doing, event by event.  In this case, I’m going to create a new Exploration report to do that.

In the left hand nav, I’ll click in to Analysis > Exploration

Under Dimensions, I’m going to add Item ID, and Item Name, and then add them to my reports Rows.

Under Metrics I’ll add Item list views, Item list clicks, Item views, and Add-to-carts and then add them to my reports Values.  

And I get a report that looks something like this:

So I can now see that for my Triblend Android T-Shirt product, it was seen in an item list once, it was clicked from an item list once, the product details were viewed once, and it was added to cart once.  This lines up with the events I actually triggered onsite, so this is looking good.

So now I’ve:

  1. Set up my App + Web tags to dual deploy alongside my Universal Analytics tags, using the Universal Analytics ecommerce object schema.
  2. I’ve triggered a series of test hits onsite to verify that the data set in them is accurate, and complete.
  3. I’ve validated that the hits are appearing in App + Web reporting as expected (with limitations relating to Product List tracking, unfortunately).


Overall, for our pre-checkout events, mapping our existing Universal Analytics ecommerce schema to App + Web tagging was pretty straightforward once I got into it.  There are some variations to what and how data that’s captured with our Universal Analytics tags, will be captured on our App + Web tags, though.  As we saw, Product List Performance tracking may be a pain point that arises from this dual deploy.  While not impossible to get powered in App + Web tagging, depending on how you implemented product list tracking in your Universal Analytics dataLayer schema, you may not be able to leverage it with a simple dual deployment of tagging.  It might require working with your development team to add additional variables to your products array, in the dataLayer itself. 

I can’t stress this enough though: App + Web is still very Beta.  So what I’m finding as gaps in the dual deployment methodology right now, may be something that will be fixed in a future release.  These gaps, and limitations of features are as expected for a Beta, and a perfect example of why we don’t recommend solely deploying App + Web on its own.  

That doesn’t mean you shouldn’t set it up at all though.  Adopting tagging/reporting for App + Web early will give you time to get accustomed to the differences and changes in reporting early, as well as comparing data collection between Universal Analytics, and App + Web first hand.

Rob English

Analytics Implementation Specialist

Analytics Implementation Specialist proficient in the use of Javascript and tag management platforms such as Google Tag Manager and TealiumIQ to build out custom tagging/tracking solutions. Google Analytics certified. Experienced in front end design and development.

See more posts from Rob