Google Analytics E-Commerce Reports and Setup of E-Commerce Events article, I discussed how to set up Google Analytics e-commerce events and which reports are associated with the relevant parameters.
In this article, I will discuss how we can use Google Tag Manager and its corresponding gtag counterparts.
First, let’s briefly revisit the dataLayer concept.
dataLayer
dataLayer is a method used by many organizations—including Google, Adobe, Yandex, and others—to store customer experience data as a JavaScript object within web or other digital platforms, enabling it to be passed to digital analytics and reporting platforms. Although “dataLayer” is a commonly used name for this object, the same functionality can be implemented under different definitions. For instance, in the Customer Experience Digital Data Layer 1.01, this structure is referred to as digitalData.
Since both the Google Tag Manager and Global Site Tag code implementations use dataLayer, I will proceed with this naming convention in my examples. However, if you’d like to modify this definition or wish to associate it with an existing JavaScript object on your website or application, you will need to update the relevant fields in the setup code2.
// Google Tag Manager (gtm)
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-TRGXFL');
// Global Site Tag (gtag)
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-59809868-2');
You can review my previous article titled What is the Data Layer (dataLayer)? How is it Used?.
Google Tag Manager and dataLayer
We mentioned that dataLayer is a JavaScript object. Therefore, we can view its contents by typing dataLayer or window.dataLayer in the browser’s console section. This object is defined as a global variable. In JavaScript, global objects are referred to as window in the browser environment, and as global in Node.js 3. Of course, we will continue our explanations using the browser. However, a note is worth adding here: the data layer definition (dataLayer) must be defined on top of the Google Tag Manager container snippet. Otherwise, no additions or modifications will be made to the data layer content managed by Google Tag Manager, and the content will be considered modified.
Let’s try this and type dataLayer in the console section. We will receive the following output: 0: Object { "gtm.start": 1602931942224, event: "gtm.js" }. Now, place the following code snippet before the Google Tag Manager container snippet and refresh the page, then view the dataLayer content again through the console.
dataLayer = [{
'pageCategory': 'signup',
'visitorType': 'high-value'
}];
As shown, new variables are now present within the dataLayer.
0: Object { pageCategory: "signup", visitorType: "high-value" }
1: Object { "gtm.start": 1602932141963, event: "gtm.js" }
Now, place these variables after the Google Tag Manager container snippet and view the content again through the console. The returned result will differ from the previous one.
0: Object { pageCategory: "signup", visitorType: "high-value" }
As can be seen, gtm.start is no longer defined. Our new definitions caused the loss of previous definitions. So, is there a solution to this? Of course there is. Since dataLayer is a JavaScript object, we can still interact with it using JavaScript. One of the options we can use is the push() method. With this method, instead of modifying the object itself, we can add new elements inside it.
dataLayer.push({'variableName': 'variableValue'});
If we want to use the above operation before the Google Tag Manager container snippet, we will encounter the error Uncaught ReferenceError: dataLayer is not defined because the dataLayer object has not yet been created. However, since the variable definition is present within the Google Tag Manger container snippet, we can use the push() method error-free after the snippet. So, is there a more general solution?
Of course, we can check for the existence of the variable and define it if it’s not already defined.
window.dataLayer = window.dataLayer || [];
dataLayer.push({'variableName': 'variableValue'});
// or
window.dataLayer.push({'variableName': 'variableValue'});
We can use the above code either before or after the Google Tag Manager container snippet. Now, we are no longer required to follow a hierarchy.
0: Object { variableName: "variableValue" }
1: Object { "gtm.start": 1602932828874, event: "gtm.js" }
Note this information aside, as we will frequently perform checks via the console when handling e-commerce events for data validation. Of course, we also need to perform checks outside of the console. For example, if an action performed does not have a corresponding counterpart in Google Tag Manager, it will be disregarded. Therefore, we must use our parameters according to specific rules.
The other extensions we can use for this purpose are Google’s Google Tag Assistant, developed by Google for Chrome browser and Adswerve - Data Layer Inspector+, provided by Adswerve, as well as dataslayer for Firefox4.
With the above pre-configuration completed, we can now proceed to perform dataLayer operations via eCommerce events.
dataLayer and E-commerce (eCommerce) Events
We will implement the following actions using dataLayer.push() for both Enhanced Ecommerce (UA) and E-commerce (GA4)2. Naturally, for these events to be processed, our Google Analytics code must be defined through Google Tag Manager, the enhanced eCommerce feature (true) must be enabled, and the data layer must be activated.
Enable Enhanced Ecommerce Features: true
Use Data Layer: true
We can now begin using our e-commerce events.
Listing/Displaying
This indicates products being listed within category and similar fields. This allows you to evaluate product listing performance (views, clicks, additions to cart, purchases).
dataLayer.push({
'ecommerce': {
'currencyCode': 'EUR',
'impressions': [
{
'name': 'Triblend Android T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Gray',
'list': 'Search Results',
'position': 1
},
{
'name': 'Donut Friday Scented T-Shirt',
'id': '67890',
'price': '33.75',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Black',
'list': 'Search Results',
'position': 2
}]
}
});
The relevant definition requires that at least one of the id or name keys must be defined. This code is associated with gtm.dom. Therefore, the Google Tag Manager container snippet must be created before this code.
dataLayer.push({
'event': 'gtm.dom',
'ecommerce': {
...
}
})
To remember the sequence: gtm.js (Page Loaded) represents the page sequence, gtm.dom (DOM Ready) represents the DOM sequence, and gtm.load (Window Loaded) represents the container sequence. Of course, there may be discrepancies in certain situations. For instance, we might need to create the impression content after the container has loaded. In such a case, what can we do?
The solution is to associate the relevant object content with a different event. For example, the content related to 'event': 'impression' can be associated with the impression event, and when this event is triggered, the object content can be sent. If the created action is not defined as a trigger, the relevant object content will not be evaluated.
dataLayer.push({
'event': 'impression',
'ecommerce': {
...
}
})
You can apply this pattern to other gtm.dom events as well. For example, when displaying products within a popup or when dynamically loading products via a carousel, you can trigger events to measure product performance. Under normal circumstances, gtm.dom content cannot be viewed in real time, but you can track it through the Conversions > Ecommerce > Product List Performance report. However, if you trigger an event, that event can then be tracked in real time as well.
Now, let’s repeat this process with Ecommerce (GA4).
dataLayer.push({
'event': 'view_item_list',
'ecommerce': {
'items': [
{
'item_name': 'Triblend Android T-Shirt',
'item_id': '12345',
'price': '15.25',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Gray',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 1,
'quantity': '1'
},
{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 2,
'quantity': '1'
}]
}
});
In Google Analytics GA4 (formerly known as App+Web), separate tag definitions are required for configuration and events. The object content shown above has the view_item_list event name and is being processed in association with gtm.dom. In certain cases, we can directly process this event definition. Please note that these GA4 object contents are not processed by the standard Google Analytics property.
Product/Item List Click
An event is triggered when a product is clicked. It has a productClick event definition, which is processed upon a click action.
dataLayer.push({
'event': 'productClick',
'ecommerce': {
'click': {
'actionField': {'list': 'Search Results'},
'products': [{
'name': 'Donut Friday Scented T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Black',
'position': 2
}]
}
}
});
Event Category: Ecommerce
Event Action: Product Click
The corresponding GA4 object content for this event is as follows.
dataLayer.push({
'event': 'select_item',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '12345',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 2,
'quantity': '1',
'price': '15.25'
}]
}
});
Product/Item Detail View
This object will also be processed via the gtm.dom event. Therefore, the guidelines under the “Listings/Views” section also apply to the reporting of this object’s content.
dataLayer.push({
'event': 'view_item',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 1,
'quantity': '1'
}]
}
});
Cart Operations
Cart operations are also user-initiated actions, similar to product clicks. The event triggered when adding an item to the cart is addToCart, and the event triggered when removing an item from the cart is removeFromCart. The object content is as follows:
dataLayer.push({
'event': 'addToCart',
'ecommerce': {
'currencyCode': 'EUR',
'add': {
'products': [{
'name': 'Triblend Android T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Gray',
'quantity': 1
}]
}
}
});
Event Category
: Ecommerce
Event Action
: Add to Cart
dataLayer.push({
'event': 'removeFromCart',
'ecommerce': {
'remove': {
'products': [{
'name': 'Triblend Android T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Gray',
'quantity': 1
}]
}
}
});
Event Category: Ecommerce
Event Action: Remove from Cart
Now let’s see how these objects are structured for GA4.
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 1,
'quantity': '2'
}]
}
});
dataLayer.push({
'event': 'remove_from_cart',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 1,
'quantity': '1'
}]
}
});
As seen in the code snippets, the events used for GA4 are add_to_cart and remove_from_cart.
Promotion View
Product display and promotion display are handled through different key definitions. Promotion performance is tracked via Marketing reports. Naturally, this process is executed using gtm.dom.
dataLayer.push({
'ecommerce': {
'promoView': {
'promotions': [
{
'id': 'JUNE_PROMO13',
'name': 'June Sale',
'creative': 'banner1',
'position': 'slot1'
},
{
'id': 'FREE_SHIP13',
'name': 'Free Shipping Promo',
'creative': 'skyscraper1',
'position': 'slot2'
}]
}
}
});
Do not forget that promoClick and promoView are evaluated differently. Therefore, they should not be triggered together. I’ll also discuss promotion clicks shortly. However, first let’s take a look at the object definition in GA4 for promotion viewing/listing.
dataLayer.push({
'event': 'view_promotion',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'promotion_id': 'abc123',
'promotion_name': 'summer_promo',
'creative_name': 'instore_suummer',
'creative_slot': '1',
'location_id': 'hero_banner',
'index': 1,
'quantity': '1'
}]
}
});
As can be seen, the relevant object is used in GA4 via the view_promotion event definition.
Promotion Click
This event is used to track a promotion (image, text, etc.) click and measure promotion performance. Relevant performance metrics are available in the Marketing section of reports. When used within a conversion, it becomes possible to evaluate the impact of the promotion on sales.
dataLayer.push({
'event': 'promotionClick',
'ecommerce': {
'promoClick': {
'promotions': [
{
'id': 'abc123',
'name': 'summer_promo',
'creative': 'instore_suummer',
'position': 1
}]
}
}
});
Event Category: Ecommerce
Event Action: Promotion Click
Let’s take a look at how this event is handled with GA4.
dataLayer.push({
'event': 'select_promotion',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'promotion_id': 'abc123',
'promotion_name': 'summer_promo',
'creative_name': 'instore_suummer',
'creative_slot': '1',
'location_id': 'hero_banner',
'index': 1,
'quantity': '1'
}]
}
});
Checkout Steps
The checkout event indicates the first step of the payment process. Together, you can examine the Checkout Labeling section under the View section, where we’ve enabled the E-commerce feature using the actionField specified values.
dataLayer.push({
'event': 'checkout',
'ecommerce': {
'checkout': {
'actionField': {'step': 1, 'option': 'Visa'},
'products': [{
'name': 'Triblend Android T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Gray',
'quantity': 1
}]
}
}
});
Event Category: Ecommerce
Event Action: Checkout
You can track the payment process steps as follows.
dataLayer.push({
'event': 'checkoutOption',
'ecommerce': {
'checkout_option': {
'actionField': {'step': 2, 'option': 'Standard Shipping'}
}
}
});
Event Category: Ecommerce
Event Action: Checkout Option
Let’s take a look at the corresponding event in GA4.
dataLayer.push({
'event': 'begin_checkout',
'ecommerce': {
'items': [{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_category_2': 'Mens',
'item_category_3': 'Shirts',
'item_category_4': 'Tshirts',
'item_variant': 'Black',
'item_list_name': 'Search Results',
'item_list_id': 'SR123',
'index': 1,
'quantity': '1'
}]
}
});
GA4 does not include step definitions for the payment process. However, you can certainly create these steps as custom events and track them using goals and funnel.
Purchase
The event triggered upon completion of the payment process is purchase. In fact, the core metrics of e-commerce reports are based on this event. This object is also evaluated in relation to gtm.dom.
dataLayer.push({
'ecommerce': {
'purchase': {
'actionField': {
'id': 'T12345',
'affiliation': 'Online Store',
'revenue': '35.43',
'tax': '4.90',
'shipping': '5.99',
'coupon': 'SUMMER_SALE'
},
'products': [{
'name': 'Triblend Android T-Shirt',
'id': '12345',
'price': '15.25',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Gray',
'quantity': 1,
'coupon': ''
},
{
'name': 'Donut Friday Scented T-Shirt',
'id': '67890',
'price': '33.75',
'brand': 'Google',
'category': 'Apparel',
'variant': 'Black',
'quantity': 1
}]
}
}
});
If the object content has been created after page load, you can evaluate the event usage related to gtm.dom as previously described.
Now let’s take a look at how the purchase event is handled in GA4.
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'purchase': {
'transaction_id': 'T12345',
'affiliation': 'Online Store',
'value': '35.43',
'tax': '4.90',
'shipping': '5.99',
'currency': 'EUR',
'coupon': 'SUMMER_SALE',
'items': [{
'item_name': 'Triblend Android T-Shirt',
'item_id': '12345',
'item_price': '15.25',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_variant': 'Gray',
'quantity': 1,
'item_coupon': ''
}, {
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'item_price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_variant': 'Black',
'quantity': 1
}]
}
}
});
Return Process
Our latest ecommerce event is refund. A refund may involve the return of one or more products, or even just a single product, or it may cover the entire purchase.
dataLayer.push({
'ecommerce': {
'refund': {
'actionField': {'id': 'T12345'}
}
}
});
The above code snippet indicates that the entire transaction record with ID T12345, previously sent via a purchase, has been refunded. We can update our snippet to specify a product or quantity return within the purchase as follows.
dataLayer.push({
'ecommerce': {
'refund': {
'actionField': {'id': 'T12345'},
'products': [
{'id': 'P4567', 'quantity': 1},
{'id': 'P8901','quantity': 2}
]
}
}
});
Now let’s see how this action is implemented in GA4.
dataLayer.push({
'event': 'refund',
'ecommerce': {
'transaction_id': 'T12345'
}
});
Yes, we’ve now covered all the details related to ecommerce events. In certain cases, you may not be able to use the dataLayer and instead have to perform actions through the GTM. In such cases, we can still perform operations without modifying the above object structure using a Custom JavaScript Variable and custom variables (also known as macros).
function() {
var ecommerceData = {
'ecommerce': {
'purchase': {
'actionField': {'id': 'T12345'},
'products': [
...
],
...
}
};
return ecommerceData;
}
In GA4, our function would look like this:
function() {
var ecommerceProductData = [
{
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
},
...
];
return ecommerceProductData;
}
Let’s assume we’ve defined this code snippet as gaEcommerceData. In this case, we can access the returned value in the format {{gaEcommerceData}}5 6. The relevant object can be linked to gtm.dom.
If you’d like to test the above operations, you can proceed by importing the JSON file located within the folder. I am regularly updating the relevant GTM folder, so I recommend you periodically check for newly added sample operations.
Footnotes
- W3.org (2013). Customer Experience Digital Data Layer 1.0. (pdf) ↩
- Renaming the Data Layer. Google Tag Manager ↩ ↩2
- Javascript.info. (2020). Global object ↩
- Adswerve - dataLayer Inspector+. Chrome Extension ↩
- Measuring Product Clicks. Google Tag Manager ↩
- Measure product/item list clicks. Google Tag Manager ↩