GA4 Ecommerce Tracking via GTM: Step-by-Step Setup Guide
Set up GA4 Ecommerce tracking via GTM with this step-by-step guide. Learn how to track transactions, product views, and more for accurate ecommerce insights.
Note: Ecommerce events can also be implemented using a global site tag (gtag.js).
With Google Analytics 4 properties, ecommerce implementation is a bit different compared to Universal Analytics.
What is GA4 Ecommerce Tracking?
Google Analytics 4 (GA4) Ecommerce Tracking is a feature through which you can track and analyze ecommerce activities on websites and mobile apps.
The e-commerce activities include viewing product details, adding items to shopping carts, making purchases, etc.
Why do you need GA4 Ecommerce Tracking?
Following are some of the key reasons why you need to implement GA4 e-commerce tracking:
- GA4 E-commerce tracking provides insights into customer behaviour on your websites and/or mobile apps.
- The ecommerce reports are used to evaluate marketing campaign effectiveness in terms of generating sales.
- E-commerce reports show customer interactions with products, including views, additions to the cart, and purchases.
- Data from the ecommerce reports helps identify popular products and customer preferences.
- Insights from e-commerce tracking are crucial for decision-making to improve online sales and improve user experience.
- By using e-commerce tracking, businesses can tailor their websites and marketing strategies to meet customer needs better, aiding growth.
- Operators of online stores or apps need more than just shopping cart analytics; GA4 E-commerce tracking is not something nice to have but a mandatory requirement.
- Through e-commerce tracking, you can correlate sales data with website usage metrics such as sessions, engagement rate, and traffic sources.
- Analyzing correlations between sales data and website usage is key to evaluating the effectiveness of landing pages and marketing campaigns.
- Without GA4 E-commerce tracking, identifying the sales impact of specific landing pages or campaigns is challenging.
Get weekly practical tips on GA4 and/or BigQuery to accurately track and read your analytics data.
GA4 vs Universal Analytics Ecommerce Tracking
If we compare Google Analytics 4 vs Universal Analytics, there are a few similarities and differences in the context of e-commerce tracking:
#1 Unlike Universal Analytics, the GA4 event-based model allows tracking a broader range of e-commerce activities. You can track any user interaction as an event, not just pre-defined ones like in Universal Analytics. This lets you capture detailed insights into specific user behaviours.
#2 GA4 allows for the creation of custom events with unique parameters. This flexibility means that specific E-commerce actions can be tracked more closely and in ways that are tailored to the business.
#3 Universal Analytics requires separate properties for tracking websites and apps. Whereas, GA4 can track both websites and apps in a single property, offering a better view of customer journeys.
#4 GA4 offers a more privacy-friendly E-commerce tracking approach compared to Universal Analytics. This is because of the following reasons:
- GA4 reduces its dependence on cookies, especially third-party cookies, which are a privacy concern.
- GA4 uses advanced machine learning algorithms to fill data gaps. This means it can provide insights without needing to collect as much personal user data.
- GA4 provides more robust user data privacy controls, allowing users to manage data collection and usage better.
The table below provides details on the different schemas and changes.
No Google
Analytics 4 Universal Analytics Description 1 view_promotion promoView When a user views a promotion 2 select_promotion promoClick When a user clicks on a promotion 3 view_item_list impressions View of product impressions in a list 4 select_item productClick Click on a product 5 view_item detail View product details 6 add_to_cart addToCart Add product to cart 7 add_to_wishlist N/A Add product to a wishlist 8 remove_from_cart removeFromCart Remove product from the cart 9 view_cart N/A View shopping cart 10 begin_checkout checkout Initiate the checkout process 11 add_shipping_info checkout_option Add shipping info during the checkout 12 add_payment_info checkout_option Add payment info during the checkout 13 purchase purchase Purchase product 14 refund refund Refund product 15 item_id id Product ID / SKU 16 item_name name Name of the product 17 item_list_name list Product list name 18 item_list_id N/A Product list identifier 19 index position Product position in the list 20 item_brand brand Product brand 21 item_category category Product category 22 item_category_2 category Product category 2nd level 23 item_category_3 category Product category 3rd level 24 item_category_4 category Product category 4th level 25 item_category_5 category Product category 5th level 26 item_variant variant Product variant name or description 27 affiliation N/A The store affiliation 28 discount N/A Any discount on product 29 coupon coupon Coupon code used 30 price price Product price 31 currency N/A User currency 32 quantity quantity Product quantity 33 promotion_id id Promotion ID 34 promotion_name name Promotion name 35 transaction_id id Unique ID for the transaction required for purchase and refund events 36 value revenue Product revenue 37 shipping shipping Shipping charges for selected product in the cart 38 payment_type option The payment method sent with add_payment_info
Tracking viewing an item from a list
To track when a user views an item from a list, push the ‘view_item_list’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_item_list",
ecommerce: {
item_list_id: "featured_products",
item_list_name: "Featured Products",
items: [
{
item_id: "SKU_98765",
item_name: "High-Performance Headphones",
affiliation: "Electronics Hub",
coupon: "AUDIO10",
discount: 15.00,
index: 0,
item_brand: "SoundPeak",
item_category: "Electronics",
item_category2: "Adult",
item_category3: "Audio Equipment",
item_category4: "Headphones",
item_category5: "Over-Ear",
item_list_id: "featured_products",
item_list_name: "Featured Products",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 85.99,
quantity: 1
},
{
item_id: "SKU_98766",
item_name: "Ergonomic Wireless Mouse",
affiliation: "Electronics Hub",
coupon: "TECH20",
discount: 5.00,
index: 1,
item_brand: "TechGear",
item_category: "Electronics",
item_category2: "Adult",
item_category3: "Computer Accessories",
item_category4: "Mice",
item_category5: "Wireless",
item_list_id: "featured_products",
item_list_name: "Featured Products",
item_variant: "Gray",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 29.99,
promotion_id: "P_98765",
promotion_name: "Tech Sale",
quantity: 2
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_item_list
Event Parameters:
items – {{Ecommerce Items}}
item_list_id – {{Ecommerce Item List ID}}
item_list_name – {{Ecommerce Item List Name}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Item List ID}} = ecommerce.item_list_id
{{Ecommerce Item List Name}} = ecommerce.item_list_name
Note: You do not need to check the “Send ecommerce data” box if you have already manually configured individual ecommerce parameters in your GA4 event tag.
If you have already manually set up individual ecommerce parameters in your GA4 event tag (like we have aready done), you have essentially done the work that the “Send ecommerce data” feature automates.
The advantage of manually configuring individual ecommerce parameters gives you more control over exactly what data is sent and how it is formatted.
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_item_list
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
We need to fire this tag on the pages where a list of products is displayed, generally on the home page, category pages, etc.
Tracking selecting an item from a list
To track when a user selects an item from a list, push the ‘select_item’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "select_item",
ecommerce: {
item_list_id: "new_arrivals",
item_list_name: "New Arrivals",
items: [
{
item_id: "SKU_98765",
item_name: "Elegant Wall Art",
affiliation: "Artistic Interiors",
coupon: "ART15",
discount: 3.50,
index: 0,
item_brand: "CreativeHome",
item_category: "Home Decor",
item_category2: "Adult",
item_category3: "Wall Decor",
item_category4: "Prints",
item_category5: "Modern Art",
item_list_id: "new_arrivals",
item_list_name: "New Arrivals",
item_variant: "Black and White",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 95.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: select_item
Event Parameters:
items – {{Ecommerce Items}}
item_list_id – {{Ecommerce Item List ID}}
item_list_name – {{Ecommerce Item List Name}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Item List ID}} = ecommerce.item_list_id
{{Ecommerce Item List Name}} = ecommerce.item_list_name
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: select_item
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking view item details
To track when a user views an item’s details, push the ‘view_item’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_item",
ecommerce: {
currency: "USD",
value: 75.95,
items: [
{
item_id: "SKU_67890",
item_name: "Designer Desk Lamp",
affiliation: "Luxury Home Decor",
coupon: "DECOR25",
discount: 5.95,
index: 0,
item_brand: "Lumina",
item_category: "Home Decor",
item_category2: "Adult",
item_category3: "Lighting",
item_category4: "Desk Lamps",
item_category5: "Modern",
item_list_id: "premium_goods",
item_list_name: "Premium Collection",
item_variant: "Chrome",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 70.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_item
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_item
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Add to cart
To track when a user adds an item to their shopping cart, push the ‘add_to_cart’ event and the associated item details to the data layer when the user adds one or more items to their shopping cart on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "add_to_cart",
ecommerce: {
currency: "USD",
value: 120.00,
items: [
{
item_id: "SKU_67890",
item_name: "Luxury Leather Wallet",
affiliation: "High-End Accessories",
coupon: "LUXE20",
discount: 20.00,
index: 0,
item_brand: "LuxBrand",
item_category: "Accessories",
item_category2: "Adult",
item_category3: "Wallets",
item_category4: "Leather",
item_category5: "Men",
item_list_id: "season_specials",
item_list_name: "Seasonal Specials",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 100.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_to_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_to_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking add to wishlist
To track when a user adds an item to their wish list, push the ‘add_to_wishlist’ event and the associated item details to the data layer when the user adds one or more items to their wish list on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "add_to_wishlist",
ecommerce: {
currency: "USD",
value: 199.99,
items: [
{
item_id: "SKU_67890",
item_name: "Professional Camera",
affiliation: "Tech Gadgets Store",
coupon: "TECH10",
discount: 20.00,
index: 0,
item_brand: "TechBrand",
item_category: "Electronics",
item_category2: "Cameras",
item_category3: "Digital Cameras",
item_category4: "Professional",
item_category5: "High Resolution",
item_list_id: "top_tech",
item_list_name: "Top Tech Picks",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 219.99,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_to_wishlist
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_to_wishlist
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking view to shopping cart
To track when a user views a shopping cart, push the ‘view_cart’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_cart",
ecommerce: {
currency: "USD",
value: 248.00,
items: [
{
item_id: "SKU_98765",
item_name: "Premium Yoga Mat",
affiliation: "Fitness Gear Shop",
coupon: "FITNESS20",
discount: 12.00,
index: 0,
item_brand: "YogaPro",
item_category: "Fitness",
item_category2: "Adult",
item_category3: "Accessories",
item_category4: "Mats",
item_category5: "Eco-Friendly",
item_list_id: "wellness_products",
item_list_name: "Wellness Collection",
item_variant: "Purple",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 130.00,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking removing an Item from Shopping Cart
To track when a user removes an item from their shopping cart, push the ‘remove_from_cart’ event and the associated item details to the data layer when a user removes one or more items from their shopping cart on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "remove_from_cart",
ecommerce: {
currency: "USD",
value: 75.00,
items: [
{
item_id: "SKU_67890",
item_name: "Elegant Evening Dress",
affiliation: "High Fashion Store",
coupon: "EVENING25",
discount: 25.00,
index: 0,
item_brand: "Fashionista",
item_category: "Apparel",
item_category2: "Women",
item_category3: "Dresses",
item_category4: "Evening Dresses",
item_category5: "Long",
item_list_id: "formal_attire",
item_list_name: "Formal Attire",
item_variant: "black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 250.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: remove_from_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: remove_from_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking views of Internal Promotions
To track when a user views an Internal promotion, push the ‘view_promotion’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_promotion",
ecommerce: {
creative_name: "Back-to-School Banner",
creative_slot: "homepage_hero",
promotion_id: "P_23456",
promotion_name: "Back-to-School Sale",
items: [
{
item_id: "SKU_67890",
item_name: "Ergonomic Backpack",
affiliation: "School Supplies Store",
coupon: "SCHOOL20",
discount: 5.00,
index: 0,
item_brand: "ErgoPack",
item_category: "School Supplies",
item_category2: "Bags",
item_category3: "Backpacks",
item_category4: "Ergonomic",
item_category5: "Adjustable Straps",
item_list_id: "back_to_school",
item_list_name: "Back to School Essentials",
item_variant: "red",
location_id: "ChIJV4RZsICnQoYRpP0WkwYYy_k",
price: 49.99,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_promotion
Event Parameters:
creative_name – {{Ecommerce Creative Name}}
creative_slot – {{Ecommerce Creative Slot}}
promotion_id – {{Ecommerce Promotion ID}}
promotion_name – {{Ecommerce Promotion Name}}
items – {{Ecommerce Items}}
Here,
{{Ecommerce Creative Name}} = ecommerce.creative_name
{{Ecommerce Creative Slot}} = ecommerce.creative_slot
{{Ecommerce Promotion ID}} = ecommerce.promotion_id
{{Ecommerce Promotion Name}} = ecommerce.promotion_name
{{Ecommerce Items}} = ecommerce.items
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_promotion
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking clicks on Internal Promotions
To track when a user clicks on an Internal promotion, push the ‘select_promotion’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object.
dataLayer.push({
event: "select_promotion",
ecommerce: {
creative_name: "Winter Campaign Banner",
creative_slot: "sidebar_2",
promotion_id: "P_67890",
promotion_name: "Winter Clearance Sale",
items: [
{
item_id: "SKU_67890",
item_name: "Cozy Winter Jacket",
affiliation: "Outdoor Gear Store",
coupon: "WINTER20",
discount: 5.00,
index: 0,
item_brand: "NorthRange",
item_category: "Outdoor Apparel",
item_category2: "Adult",
item_category3: "Outerwear",
item_category4: "Jackets",
item_category5: "Insulated",
item_list_id: "winter_specials",
item_list_name: "Winter Specials",
item_variant: "blue",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 120.00,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: select_promotion
Event Parameters:
creative_name – {{Ecommerce Creative Name}}
creative_slot – {{Ecommerce Creative Slot}}
promotion_id – {{Ecommerce Promotion ID}}
promotion_name – {{Ecommerce Promotion Name}}
items – {{Ecommerce Items}}
Here,
{{Ecommerce Creative Name}} = ecommerce.creative_name
{{Ecommerce Creative Slot}} = ecommerce.creative_slot
{{Ecommerce Promotion ID}} = ecommerce.promotion_id
{{Ecommerce Promotion Name}} = ecommerce.promotion_name
{{Ecommerce Items}} = ecommerce.items
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: select_promotion
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Measuring Checkout steps in GA4
To measure the first step in a checkout process in GA4, push the ‘begin_checkout’ event and the associated item details to the data layer on the page where the user initiates the checkout process.
This is typically the page where the user clicks a button or link to start the checkout process, such as a “Proceed to Checkout” button on the shopping cart page.
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
items: [{ // List each item in the checkout process.
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: begin_checkout
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: begin_checkout
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking coupons in GA4
To add a coupon to the ‘begin_checkout’ event in GA4, you can include the coupon code at the order or item level within the ‘items’ array.
Adding a Coupon code at the Order Level
To add a coupon code that applies to the entire order, include the ‘coupon’ parameter in the ecommerce object of the ‘begin_checkout’ event:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
coupon: "20OFFTOTAL", // Coupon applied to the whole order
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1
}
]
}
});
Adding a Coupon code at the Item Level
To add a coupon that applies to specific items, include the ‘coupon’ parameter within the relevant item objects in the ‘items’ array:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1,
coupon: "15OFFLAPTOP" // Coupon applied specifically to this item
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: begin_checkout
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: begin_checkout
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Shipping Information
When a user proceeds to the next step in the checkout process and adds shipping information, push the ‘add_shipping_info’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_shipping_info",
ecommerce: {
currency: "USD",
value: 1200.00, // Optional: Total value of the transaction.
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
item_brand: "BrandX",
item_variant: "256GB / Black",
price: 1200.00,
quantity: 1
}
]
}
});
Use the ‘shipping_tier parameter’ to specify the user’s delivery option, such as “Ground”, “Air”, or “Next-day”:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_shipping_info",
ecommerce: {
currency: "USD",
value: 1200.00, // Optional: Total value of the transaction.
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
item_brand: "BrandX",
item_variant: "256GB / Black",
price: 1200.00,
quantity: 1
}
],
shipping_tier: "Next-day" // Specify the type of shipping option chosen.
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_shipping_info
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
shipping_tier – {{Ecommerce Shipping Tier}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
{{Ecommerce Shipping Tier}} = ecommerce.shipping_tier
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_shipping_info
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking payment information during checkout
Send the ‘ add_payment_info’ event to track when users submit their payment information during checkout.
This event can be enhanced by including the ‘payment_type’ parameter, which specifies the customer’s method of payment.
Here’s how you might implement this in your data layer:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_payment_info",
ecommerce: {
payment_type: "Credit Card" // Specify the type of payment method used
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_payment_info
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
payment_type – {{Ecommerce Payment Type}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
{{Ecommerce Payment Type}} = ecommerce.shipping_tier
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_payment_info
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Purchases in GA4
To measure a purchase in GA4, push the ‘purchase’ event and the associated item details to the data layer on the order confirmation page.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "purchase",
ecommerce: {
transaction_id: "T12345",
value: 72.05,
tax: 3.60,
shipping: 5.99,
currency: "USD",
coupon: "SUMMER_SALE",
items: [
{
item_id: "SKU_67890",
item_name: "Wireless Bluetooth Mouse",
affiliation: "Tech Gear Online",
coupon: "TECH20",
discount: 5.00,
index: 0,
item_brand: "LogiTech",
item_category: "Electronics",
item_category2: "Computer Accessories",
item_category3: "Mice",
item_category4: "Wireless",
item_category5: "Bluetooth",
item_list_id: "tech_basics",
item_list_name: "Essential Tech",
item_variant: "black",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 29.99,
quantity: 2
},
{
item_id: "SKU_67891",
item_name: "Compact Portable Charger",
affiliation: "Tech Gear Online",
coupon: "CHARGE10",
discount: 3.50,
index: 1,
item_brand: "Anker",
item_category: "Electronics",
item_category2: "Power Banks",
item_category3: "Portable",
item_category4: "Battery",
item_category5: "High Capacity",
item_list_id: "travel_gear",
item_list_name: "Travel Essentials",
item_variant: "white",
promotion_id: "P_67890",
promotion_name: "Tech Travel Sale",
price: 45.00,
quantity: 1
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: purchase
Event Parameters:
items – {{Ecommerce Items}}
transaction_id – {{Ecommerce Transaction ID}}
value – {{Ecommerce Value}}
tax – {{Ecommerce Tax}}
shipping – {{Ecommerce Shipping}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Transaction ID}} = ecommerce.transaction_id
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Tax}} = ecommerce.tax
{{Ecommerce Shipping}} = ecommerce.shipping
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: purchase
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Missing Revenue in Google Analytics 4?
Sometimes, you may not see revenue data in your GA4 reports and may assume that the e-commerce tracking set-up is not correct.
There is a good possibility that you do not have permission to access revenue-related metrics for the GA4 property.
Ask your administrator to confirm that the following checkbox is not selected for you under Property > Property Access Management > {Your username} > Data restrictions (GA4 properties only)
No Revenue Metrics.
When the ‘No Revenue Metrics’ checkbox is selected for you, ecommerce reports tend not to be accurate for you, and you can not access any of the ‘revenue-related metrics’ in your GA4 reports.
For example, when the ‘No Revenue Metrics’ checkbox is selected for you, the transactions report may appear like the one below with no data for ‘Ecommerce purchase quantity’ and ‘Purchase revenue’ metrics.
Tracking Refunds in GA4
Refund tracking in GA4 can be implemented by pushing the ‘refund’ event into the dataLayer.
The ‘refund’ event must include a transaction ID to be correctly associated with the original purchase.
For a full refund, push the ‘refund’ event with the transaction ID to the data layer:
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object to ensure clean data.
dataLayer.push({
event: "refund",
ecommerce: {
transaction_id: "T67890" // Unique identifier for the transaction being refunded.
// No item details needed for a full transaction refund
}
});
To track a partial refund in GA4 include both the transaction ID and specific item details of the refunded items in the dataLayer.push event.
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object.
dataLayer.push({
event: "refund",
ecommerce: {
transaction_id: "T67890", // Unique identifier for the transaction being partially refunded.
items: [{ // Array of items being partially refunded.
item_id: "SKU_67891", // Unique identifier for the item.
price: 29.99, // Price per unit of the item.
quantity: 1 // Number of units being refunded.
}]
}
});
Including detailed item information in GA4’s refund tracking allows for calculating specific metrics like the Item Refund Amount and the adjusted Item Revenue after refunds.
This granularity provides deeper insights into refund patterns by showing which products are most frequently returned and their overall impact on revenue, enabling better inventory and sales strategy adjustments.
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: refund
Event Parameters:
items – {{Ecommerce Items}}
transaction_id – {{Ecommerce Transaction ID}}
value – {{Ecommerce Value}}
tax – {{Ecommerce Tax}}
shipping – {{Ecommerce Shipping}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Transaction ID}} = ecommerce.transaction_id
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Tax}} = ecommerce.tax
{{Ecommerce Shipping}} = ecommerce.shipping
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: refund
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
If you see negative values for the ‘Purchase revenue’ or ‘Total revenue’ metrics or $0 value for the ‘Gross purchase revenue’ metric in GA4, it could be because of the refund transaction(s).
Both the ‘Purchase revenue’ and ‘Total revenue’ metrics take refunds into account.
In GA4, both the ‘Purchase revenue’ and ‘Total revenue’ metrics take refunds into account (which is created by firing the ‘refund’ event).
However, the ‘Gross purchase revenue’ metric does not take refund into account. But its value would be zero in case of the refund transaction.
So if you see negative values for the ‘Purchase revenue’ or ‘Total revenue’ metrics or $0 value for the ‘Gross purchase revenue’ metric, apply a secondary dimension called ‘Event name’ to check whether the transaction is recorded because of the ‘purchase’ or ‘refund’ event.
Refund is a type of transaction in GA4.
In GA4, a refund is counted as a transaction, and it impacts your total transaction count.
So, not all transactions are purchase events. They could also include refund events.
So, there are two categories of GA4 transactions:
- Purchase transactions.
- Refund transactions.
When reporting on e-commerce data, make sure that you segment the data based on purchases and refunds.
This segmentation allows for a clear distinction between revenue-generating transactions and refunds, providing a more precise picture of your e-commerce performance.
It is also equally important to segment the e-commerce data for web and app by using the ‘Stream name’ dimension if you also use mobile apps in addition to a website.
If you want to report on the total number of refunds and refund amount in GA4 reports, then use the ‘Refunds’ and ‘Refund amount’ metrics:
However, these metrics are not available by default in standard reports. You will have to customize your report to add them.
So, that is how you can set up ecommerce tracking in Google Analytics 4.
Top Implementation Mistakes in GA4 Ecommerce Tracking
Beware of these 7 common implementation mistakes in your GA4 ecommerce tracking:
- Not looking at the ‘Event count per user’ metric’ for ecommerce events.
- Not tracking state changes.
- Not using a throttling function.
- Not using debouncing techniques.
- Not clearing the ecommerce data in the data layer.
- Not including all relevant event parameters with each ecommerce event.
- Not involving client’s web developers/IT team.
Mistake #1: Not looking at the ‘Event count per user’ metric’ for ecommerce events.
It is common to see inflated ecommerce events in a GA4 property because most developers do not set up ecommerce tracking correctly.
A quick way to check for duplicate ecommerce events in GA4 is to look at the ‘Event Count Per user’ metric.
A high event count per user can be a sign of duplicate ecommerce events.
For example, it is very unlikely for a typical user to add payment information 23 times repeatedly.
Mistake #2: Not tracking state changes.
It is common to see inflated ecommerce events in a GA4 property because most developers do not track state changes but rather send duplicate events to GA4.
If a user repeatedly performs an action (e.g., clicking an “add to cart” button multiple times), tracking state changes helps you avoid counting each click as a separate event, which could inflate your ‘add to cart’ metric and provide an inaccurate view of user behaviour.
Consider a scenario where a user is adjusting the quantity of an item in their shopping cart:
Without State Change Tracking:
You might send an ‘add_to_cart’ event whenever the user changes the quantity.
If the user increases the quantity from 1 to 5, one unit at a time, this might result in 5 separate ‘add_to_cart’ events, leading to duplicate events.
With State Change Tracking:
You can send a single custom event, like ‘cart_quantity_updated’, along with parameters that reflect the old and new quantities.
This provides a more accurate view of the user’s actions without creating duplicate events.
Tracking state changes rather than sending duplicate events in GA4 can provide a more accurate representation of user interactions on your website.
Below, I provide a simple example using JavaScript that checks whether an item has already been added to the cart before sending an event to GA4. This example assumes you’re working in a browser environment where session storage is available:
// Function to add item to the cart
function addToCart(itemId, quantity) {
const cartKey = 'userCart';
let cart = JSON.parse(sessionStorage.getItem(cartKey)) || {};
// Check if the item already exists in the cart
if (cart[itemId]) {
// Item exists, update the quantity if different
if (cart[itemId] !== quantity) {
cart[itemId] = quantity;
// Send update to GA4 as a state change
trackEventGA4('update_cart', { itemId: itemId, quantity: quantity });
}
} else {
// Item does not exist, add new item
cart[itemId] = quantity;
// Send add to cart event to GA4
trackEventGA4('add_to_cart', { itemId: itemId, quantity: quantity });
}
// Update the cart in session storage
sessionStorage.setItem(cartKey, JSON.stringify(cart));
}
// Function to track events in GA4
function trackEventGA4(eventName, eventParams) {
console.log(`Tracking event: ${eventName}`, eventParams); // Placeholder for GA4 tracking code
// gtag('event', eventName, eventParams); Uncomment this and configure gtag for your GA4
}
// Example usage
document.getElementById('addToCartButton').addEventListener('click', function() {
const itemId = this.getAttribute('data-item-id');
const quantity = parseInt(this.getAttribute('data-quantity'), 10);
addToCart(itemId, quantity);
});
You can use a data layer to manage and track state changes effectively.
The data layer can hold information about the current state and can be used to trigger specific tags based on changes to that state.
// Initialize the data layer object
window.dataLayer = window.dataLayer || [];
// Function to update data layer when a product is added to the cart
function updateDataLayer(eventAction, product) {
window.dataLayer.push({
event: eventAction,
ecommerce: {
currency: 'USD',
items: [{
item_id: product.id,
item_name: product.name,
item_category: product.category,
price: product.price,
quantity: product.quantity,
item_variant: product.variant || 'default',
item_list_name: product.listName || 'Search Results',
item_list_id: product.listId || 'SR123',
index: product.index || 0
}]
}
});
}
// Example product data
const exampleProduct = {
id: 'P12345',
name: 'Awesome Widget',
category: 'Gadgets',
price: 19.99,
quantity: 1
};
// Simulate adding an item to the cart
updateDataLayer('add_to_cart', exampleProduct);
GA4 allows for custom parameters with events, enabling you to send additional information about the state change (e.g., the old and new quantities).
Let’s assume you want to track how users update the item quantities in their shopping carts.
Here’s how you could structure the event data with custom parameters to capture both the old and new quantities:
// Function to track changes in the item quantity in the shopping cart
function trackQuantityChange(itemId, oldQuantity, newQuantity) {
// Send the event to GA4 with custom parameters
gtag('event', 'update_quantity', {
'item_id': itemId,
'old_quantity': oldQuantity,
'new_quantity': newQuantity
});
}
// Example usage of the function
trackQuantityChange('P12345', 1, 3);
Your ecommerce tracking in GA4 is unlikely to be ever accurate if you do not track state changes.
Mistake #3: Not using a throttling function.
A throttling function is another good method to prevent sending duplicate ecommerce events to GA4.
For example, a throttling function ensures that the ‘purchase’ event is not fired more than once when the order confirmation page reloads by a user. This would prevent duplicate ‘purchase’ events.
Following is an example of how you could implement a simple throttling function in JavaScript which ensures that a ‘purchase’ event isn’t sent to GA4 more than once within a specified time frame, such as when a user may accidentally or intentionally reload an order confirmation page:
// Throttle function to limit how often a callback can be executed
function throttle(callback, limit) {
var waiting = false; // Initially, no throttle is being applied
return function () {
if (!waiting) {
callback.apply(this, arguments);
waiting = true; // Throttle subsequent calls
setTimeout(function () {
waiting = false; // After a period, allow future calls
}, limit);
}
};
}
// Function to send a purchase event to GA4
function trackPurchaseEvent() {
console.log("Purchase event tracked"); // Placeholder for actual tracking code
// gtag('event', 'purchase', { /* event parameters */ });
}
// Throttled version of the trackPurchaseEvent function
const throttledTrackPurchase = throttle(trackPurchaseEvent, 5000); // Only allow a purchase event every 5 seconds
// Example of how to use the throttled function
document.getElementById('confirmButton').addEventListener('click', throttledTrackPurchase);
Your ecommerce tracking in GA4 is unlikely to be ever accurate if you do not use a throttling function.
Mistake #4: Not using debouncing techniques.
Implementing debouncing techniques can effectively prevent rapid, repeated actions from causing duplication in your ecommerce tracking.
Debouncing ensures that a function does not execute until a certain amount of time has passed since the last time the function was executed.
This technique can be useful for preventing rapid, repeated clicks, say on a ‘Complete Order’ button, from causing duplicate ‘purchase’ events.
The following example shows how to implement a debounce function in JavaScript to prevent duplicate purchase events from being fired due to repeated clicks on a ‘complete order’ button:
// Debounce function to limit how often a function can run
function debounce(func, delay) {
let debounceTimer;
return function() {
const context = this;
const args = arguments;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => func.apply(context, args), delay);
};
}
// Function to send a purchase event to GA4
function trackPurchaseEvent() {
console.log("Purchase event tracked"); // Placeholder for actual tracking code
// gtag('event', 'purchase', { /* event parameters here */ });
}
// Debounced version of the trackPurchaseEvent function
const debouncedTrackPurchase = debounce(trackPurchaseEvent, 2000); // 2000 milliseconds delay
// Setup event listener for the complete order button
document.getElementById('completeOrderButton').addEventListener('click', debouncedTrackPurchase);
Difference between Debouncing and Throttling.
Debouncing delays the function execution until there is a pause in the event triggering the function. Whereas, throttling controls the execution frequency to a fixed rate, ensuring the function executes at regular intervals.
Mistake #5: Not clearing the ecommerce data in the data layer.
Always clear the ecommerce data in the data layer before pushing a new transaction event in GA4.
dataLayer.push({ ‘ecommerce’: null }); // Clear previous data
By clearing past data, you ensure the new transaction event reflects the current state, preventing contamination from previous actions like adding or removing items.
Mixed data points from different transactions can cause errors in tracking and reporting.
Example:
Suppose a customer adds a laptop-x1 and then later removes it, only to add a different model (laptop-y2) to their cart.
If the ecommerce data isn’t cleared before the new transaction data is pushed, both laptops might incorrectly appear in the transaction details, leading to errors in sales tracking:
// Initial incorrect state in the dataLayer
dataLayer = {
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-x1"} // From step 1 (incorrect)
]
}
}
};
// When Laptop Y2 is added
dataLayer.push({
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-x1"}, // Still present (incorrect)
{"id": "laptop-y2"} // Newly added (correct)
]
}
}
});
When adding a new item (laptop-y2) after clearing the data, ensure that only the relevant, current items are reflected in the data layer.
dataLayer.push({ 'ecommerce': null }); // Clears the previous ecommerce data for accuracy
dataLayer.push({
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-y2"} // Correctly reflects the current cart content
]
}
}
});
This action keeps the cart and inventory data accurate.
Mistake #6: Not including all relevant event parameters with each ecommerce event.
Each e-commerce event in GA4 requires specific event parameters to be included.
If these event parameters are missing or incorrectly configured, GA4 will display “(not set)” as a placeholder value.
For example,
If the ‘item_name’ parameter is not included in the ‘add_to_cart’ event, the item name will appear as “(not set)” in the e-commerce reports.
Mistake #7: Not involving client’s web developers/IT team.
Are you trying to install GA4 ecommerce tracking all by yourself?
Q. Can you code a server-side language (like PHP)?
Q. Do you know how to programmatically query a database?
Q. Do you understand the Google Analytics development environment like the back of your hand?
Q. Do you understand your client’s development environment/database?
If the answer to any of the above questions is ‘NO’ then you won’t be able to install ecommerce tracking all by yourself.
Often, marketers who attempt to install ecommerce tracking have developed a false belief that they can set up all types of tracking by themselves through GTM.
That they can somehow become independent from the IT/Web developer.
They overestimate their abilities because Google has been preaching to them for years that GTM makes you independent of web developers.
Even when you have adequate knowledge of HTML, DOM, and JavaScript, you would still need the help of the client’s web developers/IT to add server-side code to your data layers or to query their database for you.
Without adding server-side code to GTM data layers, you can not implement ecommerce tracking in GA4.
Monetization Reports in Google Analytics 4
Once you have set up ecommerce tracking in GA4, you can access the various ecommerce reports in your GA4 property under ‘Monetization’.
In the context of GA4, the e-commerce reports are known as the Monetization reports.
The following monetization reports are available in GA4:
- Monetization Overview Report.
- Ecommerce Purchases Report.
- In-app purchases Report.
- Publisher ads Report.
- Promotions Report.
- User Purchase Journey Report.
- Order Coupon Report.
- Item list Report.
- Checkout Journey Report.
Update: New dimensions and metrics for ecommerce in GA4
GA4 has introduced new dimensions and metrics for ecommerce.
It also now provides an event-scoped and item-scoped version of ecommerce metrics and dimensions.
Event-scoped metrics measure the number of times an ecommerce event was triggered on your website/app.
For example,
‘Add to carts‘ is an event-scoped metric that measures the number of times users add items to a shopping cart.
This metric is populated by sending the add_to_cart event.
Item-scoped metrics measure the number of items users interacted with on your website/app.
For example,
‘Items added to cart‘ is an item-scoped metric that measures the number of items added to the cart.
This metric is populated by sending an items array with the add_to_cart event.
Just like GA4 ecommerce metrics, there are event-scoped and item-scoped dimensions.
“Item-scoped and event-scoped dimensions and metrics are incompatible with one another. Any time you use an item-scoped dimension, you must select an item-scoped metric rather than the equivalent event-scoped metric. The same applies to event-scoped dimensions and metrics.” – Google
The new ecommerce dimensions and metrics are found in exploration reports and the data API:
1) Item affiliation – The name or code of the affiliate associated with an item you sell.
2) Item variant – Like small, medium, large.
3) Items added to cart – number of items added to the cart.
4) Items checked out – number of items that were in the cart during checkout.
5) Items clicked in list – number of items clicked in a product list.
6) Items clicked in promotion – number of items clicked in a promotion.
7) Items viewed – number of items viewed.
8) Items viewed in list – number of items viewed in a product list.
9) Items viewed in promotion – number of items viewed in a promotion.
10) Shipping amount – the shipping amount associated with a transaction.
11) Shipping tier – different levels of shipping services offered by a company like standard, expedited, one-day delivery etc.
12) Tax amount – the tax amount associated with a transaction.
GA4 renamed the following ecommerce metrics:
- Add to carts (previously called Add-to-carts)
- Item-list click events (previously called Item list clicks)
- Item-list view events (previously called Item list views)
- Item view events (previously called Item views)
- Items purchased (previously called Item purchase quantity)
- Promotion clicks (previously called Item promotion clicks)
- Promotion views (previously called Item promotion views)
FAQ: We see a discrepancy in Sales in GA4 compared to UA (UA is closer to Shopify data, which is the most accurate). How do we fix this?
For purchase data between UA (Universal Analytics) and GA4, we are able to consistently match 90% or higher.
On one of the websites, we matched up to 98% of the purchase data between Universal Analytics and GA4.
Up to 10% of data discrepancy between Universal Analytics and GA4 purchase data is normal, as Universal Analytics and GA4 use different measurement models, and then there are other factors involved (like data threshold, data retention, data sampling, cardinality etc.).
However, if the data discrepancy is more than 20%, something is most likely wrong with your GA4 ecommerce tracking setup.
The more marketing channels you use to generate sales, the harder it becomes to fix discrepancies between Universal Analytics and GA4 purchase data or data discrepancies between GA4 and Shopping Cart purchase data.
To fix data discrepancies, the first step is to compare your purchase data by marketing channels between Universal Analytics and GA4 to identify patterns and potential causes for the discrepancies.
Suppose you concluded that Universal Analytics reported $20k in sales from Facebook ads in the last month, but GA4 reported only $9k in sales from Facebook ads during the same time period.
The next step is to figure out why GA4 is underreporting sales from Facebook ads.
Is it because of UTM parameters, data threshold, data sampling, recent IOS update or something else?
Facebook is often the channel that is the hardest to track in generating sales because of IOS 14.5+ updates.
Use the Facebook Conversion API (CAPI) along with your Facebook pixel to get more conversion data from Facebook ads.
If you can’t figure out why GA4 is underreporting sales from Facebook ads, compare the Universal Analytics purchase data with GA4 BigQuery export purchase data.
The GA4 BigQuery export data does not suffer from data sampling, data thresholding or cardinality limits issues.
So if you see a lot of data discrepancy between GA4 BigQuery export data and the data from the GA4 UI or data API, it means one or all the following factors result in underreporting: data threshold, data retention, data sampling, cardinality etc.
You have room for improvement if you don’t see a lot of data discrepancy between GA4 BigQuery export data and the data from the GA4 UI or data API.
Bear in mind that due to enhanced ecommerce tracking, Universal Analytics can track a lot more ecommerce data than GA4. So it is not really apple to apple comparison.
While setting up ecommerce tracking in GA4, build a mechanism to handle the following by adjusting the sales data to reflect the changes: cancelled orders, unfulfilled orders, test orders, promotions (promo codes, discounts) and refunds (partial or full).
If your website supports multiple currencies during checkout, this could create data discrepancy issues between GA4 and your shopping cart. Wherever possible, use one currency for checkout.
Finally, choose a shopping cart that fully supports GA4.
Universal Analytics has been around for decades. So many shopping carts and plugins fully support Universal Analytics.
But this is not the case with GA4 which could result in the underreporting of sales data or other data discrepancies.
How to find duplicate transactions in GA4?
Two or more transactions with the same transaction ID are called duplicate transactions.
GA4 automatically de-duplicates transactions with the same transaction ID from the same user.
However, if the same transaction ID is used for different users, such transactions are not automatically de-duplicated by GA4.
You will first need to find duplicate transactions in your GA4 property and then ask your developer to fix them.
Look at the ‘Purchases’ column of your exploration report. They should all be 1.
If you find any value greater than 1, you have got duplicate transaction issue.
For more details on GA4 duplicate transactions, check out this article: Duplicate Transactions (orders) in Google Analytics 4.
Ecommerce Conversion Rate in Google Analytics 4 (GA4)
Unlike Universal Analytics, GA4 does not provide e-commerce conversion rate metric. It is missing for no apparent reason. However, there is a workaround.
You can use the ‘Session Conversion Rate‘ metric as an e-commerce conversion rate metric via the exploration report.
To learn more, check out this article: GA4 Ecommerce Conversion Rate – How to find and use it.
Other articles on Google Analytics Ecommerce
- Google Analytics Ecommerce Tracking Tutorial
- Enhanced Ecommerce Tracking in Google Analytics – Tutorial
- Set up Enhanced Ecommerce Tracking in Google Analytics
- Using Enhanced Ecommerce segments for Remarketing in Google Analytics
- Using Cohort Analysis & Enhanced Ecommerce to Understand User Behavior
- Duplicate Transactions (orders) in Google Analytics
- Enhanced Ecommerce Tracking via Google Tag Manager
- Ecommerce Tracking Google Tag Manager (GTM) – Tutorial
- Shopify Enhanced Ecommerce Tracking in Google Analytics – Tutorial
- Why Google Analytics and Shopping Cart Sales data don’t match and how to fix it
- How to remove / modify Google Analytics ecommerce transaction in one click
- Tracking Google Analytics Paypal Referral and other payment gateways
- Subscription & Recurring Revenue Analytics in Google Analytics
- Understanding Google Analytics Product Data Import
- Shopping Cart Analytics Tutorial
- Learn To Read E-Commerce Reports In Google Analytics
- Dealing with Google Analytics Refund – Reverse Transaction
- How to reverse transactions in Google Analytics for gtag.js and analytics.js
- How to Fix Missing Ecommerce Data in Google Analytics
Set up GA4 Ecommerce tracking via GTM with this step-by-step guide. Learn how to track transactions, product views, and more for accurate ecommerce insights.
Note: Ecommerce events can also be implemented using a global site tag (gtag.js).
With Google Analytics 4 properties, ecommerce implementation is a bit different compared to Universal Analytics.
What is GA4 Ecommerce Tracking?
Google Analytics 4 (GA4) Ecommerce Tracking is a feature through which you can track and analyze ecommerce activities on websites and mobile apps.
The e-commerce activities include viewing product details, adding items to shopping carts, making purchases, etc.
Why do you need GA4 Ecommerce Tracking?
Following are some of the key reasons why you need to implement GA4 e-commerce tracking:
- GA4 E-commerce tracking provides insights into customer behaviour on your websites and/or mobile apps.
- The ecommerce reports are used to evaluate marketing campaign effectiveness in terms of generating sales.
- E-commerce reports show customer interactions with products, including views, additions to the cart, and purchases.
- Data from the ecommerce reports helps identify popular products and customer preferences.
- Insights from e-commerce tracking are crucial for decision-making to improve online sales and improve user experience.
- By using e-commerce tracking, businesses can tailor their websites and marketing strategies to meet customer needs better, aiding growth.
- Operators of online stores or apps need more than just shopping cart analytics; GA4 E-commerce tracking is not something nice to have but a mandatory requirement.
- Through e-commerce tracking, you can correlate sales data with website usage metrics such as sessions, engagement rate, and traffic sources.
- Analyzing correlations between sales data and website usage is key to evaluating the effectiveness of landing pages and marketing campaigns.
- Without GA4 E-commerce tracking, identifying the sales impact of specific landing pages or campaigns is challenging.
GA4 vs Universal Analytics Ecommerce Tracking
If we compare Google Analytics 4 vs Universal Analytics, there are a few similarities and differences in the context of e-commerce tracking:
#1 Unlike Universal Analytics, the GA4 event-based model allows tracking a broader range of e-commerce activities. You can track any user interaction as an event, not just pre-defined ones like in Universal Analytics. This lets you capture detailed insights into specific user behaviours.
#2 GA4 allows for the creation of custom events with unique parameters. This flexibility means that specific E-commerce actions can be tracked more closely and in ways that are tailored to the business.
#3 Universal Analytics requires separate properties for tracking websites and apps. Whereas, GA4 can track both websites and apps in a single property, offering a better view of customer journeys.
#4 GA4 offers a more privacy-friendly E-commerce tracking approach compared to Universal Analytics. This is because of the following reasons:
- GA4 reduces its dependence on cookies, especially third-party cookies, which are a privacy concern.
- GA4 uses advanced machine learning algorithms to fill data gaps. This means it can provide insights without needing to collect as much personal user data.
- GA4 provides more robust user data privacy controls, allowing users to manage data collection and usage better.
The table below provides details on the different schemas and changes.
No | Google Analytics 4 | Universal Analytics | Description |
1 | view_promotion | promoView | When a user views a promotion |
2 | select_promotion | promoClick | When a user clicks on a promotion |
3 | view_item_list | impressions | View of product impressions in a list |
4 | select_item | productClick | Click on a product |
5 | view_item | detail | View product details |
6 | add_to_cart | addToCart | Add product to cart |
7 | add_to_wishlist | N/A | Add product to a wishlist |
8 | remove_from_cart | removeFromCart | Remove product from the cart |
9 | view_cart | N/A | View shopping cart |
10 | begin_checkout | checkout | Initiate the checkout process |
11 | add_shipping_info | checkout_option | Add shipping info during the checkout |
12 | add_payment_info | checkout_option | Add payment info during the checkout |
13 | purchase | purchase | Purchase product |
14 | refund | refund | Refund product |
15 | item_id | id | Product ID / SKU |
16 | item_name | name | Name of the product |
17 | item_list_name | list | Product list name |
18 | item_list_id | N/A | Product list identifier |
19 | index | position | Product position in the list |
20 | item_brand | brand | Product brand |
21 | item_category | category | Product category |
22 | item_category_2 | category | Product category 2nd level |
23 | item_category_3 | category | Product category 3rd level |
24 | item_category_4 | category | Product category 4th level |
25 | item_category_5 | category | Product category 5th level |
26 | item_variant | variant | Product variant name or description |
27 | affiliation | N/A | The store affiliation |
28 | discount | N/A | Any discount on product |
29 | coupon | coupon | Coupon code used |
30 | price | price | Product price |
31 | currency | N/A | User currency |
32 | quantity | quantity | Product quantity |
33 | promotion_id | id | Promotion ID |
34 | promotion_name | name | Promotion name |
35 | transaction_id | id | Unique ID for the transaction required for purchase and refund events |
36 | value | revenue | Product revenue |
37 | shipping | shipping | Shipping charges for selected product in the cart |
38 | payment_type | option | The payment method sent with add_payment_info |
Tracking viewing an item from a list
To track when a user views an item from a list, push the ‘view_item_list’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_item_list",
ecommerce: {
item_list_id: "featured_products",
item_list_name: "Featured Products",
items: [
{
item_id: "SKU_98765",
item_name: "High-Performance Headphones",
affiliation: "Electronics Hub",
coupon: "AUDIO10",
discount: 15.00,
index: 0,
item_brand: "SoundPeak",
item_category: "Electronics",
item_category2: "Adult",
item_category3: "Audio Equipment",
item_category4: "Headphones",
item_category5: "Over-Ear",
item_list_id: "featured_products",
item_list_name: "Featured Products",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 85.99,
quantity: 1
},
{
item_id: "SKU_98766",
item_name: "Ergonomic Wireless Mouse",
affiliation: "Electronics Hub",
coupon: "TECH20",
discount: 5.00,
index: 1,
item_brand: "TechGear",
item_category: "Electronics",
item_category2: "Adult",
item_category3: "Computer Accessories",
item_category4: "Mice",
item_category5: "Wireless",
item_list_id: "featured_products",
item_list_name: "Featured Products",
item_variant: "Gray",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 29.99,
promotion_id: "P_98765",
promotion_name: "Tech Sale",
quantity: 2
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_item_list
Event Parameters:
items – {{Ecommerce Items}}
item_list_id – {{Ecommerce Item List ID}}
item_list_name – {{Ecommerce Item List Name}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Item List ID}} = ecommerce.item_list_id
{{Ecommerce Item List Name}} = ecommerce.item_list_name
Note: You do not need to check the “Send ecommerce data” box if you have already manually configured individual ecommerce parameters in your GA4 event tag.
If you have already manually set up individual ecommerce parameters in your GA4 event tag (like we have aready done), you have essentially done the work that the “Send ecommerce data” feature automates.
The advantage of manually configuring individual ecommerce parameters gives you more control over exactly what data is sent and how it is formatted.
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_item_list
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
We need to fire this tag on the pages where a list of products is displayed, generally on the home page, category pages, etc.
Tracking selecting an item from a list
To track when a user selects an item from a list, push the ‘select_item’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "select_item",
ecommerce: {
item_list_id: "new_arrivals",
item_list_name: "New Arrivals",
items: [
{
item_id: "SKU_98765",
item_name: "Elegant Wall Art",
affiliation: "Artistic Interiors",
coupon: "ART15",
discount: 3.50,
index: 0,
item_brand: "CreativeHome",
item_category: "Home Decor",
item_category2: "Adult",
item_category3: "Wall Decor",
item_category4: "Prints",
item_category5: "Modern Art",
item_list_id: "new_arrivals",
item_list_name: "New Arrivals",
item_variant: "Black and White",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 95.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: select_item
Event Parameters:
items – {{Ecommerce Items}}
item_list_id – {{Ecommerce Item List ID}}
item_list_name – {{Ecommerce Item List Name}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Item List ID}} = ecommerce.item_list_id
{{Ecommerce Item List Name}} = ecommerce.item_list_name
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: select_item
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking view item details
To track when a user views an item’s details, push the ‘view_item’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_item",
ecommerce: {
currency: "USD",
value: 75.95,
items: [
{
item_id: "SKU_67890",
item_name: "Designer Desk Lamp",
affiliation: "Luxury Home Decor",
coupon: "DECOR25",
discount: 5.95,
index: 0,
item_brand: "Lumina",
item_category: "Home Decor",
item_category2: "Adult",
item_category3: "Lighting",
item_category4: "Desk Lamps",
item_category5: "Modern",
item_list_id: "premium_goods",
item_list_name: "Premium Collection",
item_variant: "Chrome",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 70.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_item
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_item
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Add to cart
To track when a user adds an item to their shopping cart, push the ‘add_to_cart’ event and the associated item details to the data layer when the user adds one or more items to their shopping cart on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "add_to_cart",
ecommerce: {
currency: "USD",
value: 120.00,
items: [
{
item_id: "SKU_67890",
item_name: "Luxury Leather Wallet",
affiliation: "High-End Accessories",
coupon: "LUXE20",
discount: 20.00,
index: 0,
item_brand: "LuxBrand",
item_category: "Accessories",
item_category2: "Adult",
item_category3: "Wallets",
item_category4: "Leather",
item_category5: "Men",
item_list_id: "season_specials",
item_list_name: "Seasonal Specials",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 100.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_to_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_to_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking add to wishlist
To track when a user adds an item to their wish list, push the ‘add_to_wishlist’ event and the associated item details to the data layer when the user adds one or more items to their wish list on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "add_to_wishlist",
ecommerce: {
currency: "USD",
value: 199.99,
items: [
{
item_id: "SKU_67890",
item_name: "Professional Camera",
affiliation: "Tech Gadgets Store",
coupon: "TECH10",
discount: 20.00,
index: 0,
item_brand: "TechBrand",
item_category: "Electronics",
item_category2: "Cameras",
item_category3: "Digital Cameras",
item_category4: "Professional",
item_category5: "High Resolution",
item_list_id: "top_tech",
item_list_name: "Top Tech Picks",
item_variant: "Black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 219.99,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_to_wishlist
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_to_wishlist
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking view to shopping cart
To track when a user views a shopping cart, push the ‘view_cart’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_cart",
ecommerce: {
currency: "USD",
value: 248.00,
items: [
{
item_id: "SKU_98765",
item_name: "Premium Yoga Mat",
affiliation: "Fitness Gear Shop",
coupon: "FITNESS20",
discount: 12.00,
index: 0,
item_brand: "YogaPro",
item_category: "Fitness",
item_category2: "Adult",
item_category3: "Accessories",
item_category4: "Mats",
item_category5: "Eco-Friendly",
item_list_id: "wellness_products",
item_list_name: "Wellness Collection",
item_variant: "Purple",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 130.00,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking removing an Item from Shopping Cart
To track when a user removes an item from their shopping cart, push the ‘remove_from_cart’ event and the associated item details to the data layer when a user removes one or more items from their shopping cart on your website or app.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "remove_from_cart",
ecommerce: {
currency: "USD",
value: 75.00,
items: [
{
item_id: "SKU_67890",
item_name: "Elegant Evening Dress",
affiliation: "High Fashion Store",
coupon: "EVENING25",
discount: 25.00,
index: 0,
item_brand: "Fashionista",
item_category: "Apparel",
item_category2: "Women",
item_category3: "Dresses",
item_category4: "Evening Dresses",
item_category5: "Long",
item_list_id: "formal_attire",
item_list_name: "Formal Attire",
item_variant: "black",
location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
price: 250.00,
quantity: 1
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: remove_from_cart
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: remove_from_cart
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking views of Internal Promotions
To track when a user views an Internal promotion, push the ‘view_promotion’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "view_promotion",
ecommerce: {
creative_name: "Back-to-School Banner",
creative_slot: "homepage_hero",
promotion_id: "P_23456",
promotion_name: "Back-to-School Sale",
items: [
{
item_id: "SKU_67890",
item_name: "Ergonomic Backpack",
affiliation: "School Supplies Store",
coupon: "SCHOOL20",
discount: 5.00,
index: 0,
item_brand: "ErgoPack",
item_category: "School Supplies",
item_category2: "Bags",
item_category3: "Backpacks",
item_category4: "Ergonomic",
item_category5: "Adjustable Straps",
item_list_id: "back_to_school",
item_list_name: "Back to School Essentials",
item_variant: "red",
location_id: "ChIJV4RZsICnQoYRpP0WkwYYy_k",
price: 49.99,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: view_promotion
Event Parameters:
creative_name – {{Ecommerce Creative Name}}
creative_slot – {{Ecommerce Creative Slot}}
promotion_id – {{Ecommerce Promotion ID}}
promotion_name – {{Ecommerce Promotion Name}}
items – {{Ecommerce Items}}
Here,
{{Ecommerce Creative Name}} = ecommerce.creative_name
{{Ecommerce Creative Slot}} = ecommerce.creative_slot
{{Ecommerce Promotion ID}} = ecommerce.promotion_id
{{Ecommerce Promotion Name}} = ecommerce.promotion_name
{{Ecommerce Items}} = ecommerce.items
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: view_promotion
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking clicks on Internal Promotions
To track when a user clicks on an Internal promotion, push the ‘select_promotion’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object.
dataLayer.push({
event: "select_promotion",
ecommerce: {
creative_name: "Winter Campaign Banner",
creative_slot: "sidebar_2",
promotion_id: "P_67890",
promotion_name: "Winter Clearance Sale",
items: [
{
item_id: "SKU_67890",
item_name: "Cozy Winter Jacket",
affiliation: "Outdoor Gear Store",
coupon: "WINTER20",
discount: 5.00,
index: 0,
item_brand: "NorthRange",
item_category: "Outdoor Apparel",
item_category2: "Adult",
item_category3: "Outerwear",
item_category4: "Jackets",
item_category5: "Insulated",
item_list_id: "winter_specials",
item_list_name: "Winter Specials",
item_variant: "blue",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 120.00,
quantity: 2
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: select_promotion
Event Parameters:
creative_name – {{Ecommerce Creative Name}}
creative_slot – {{Ecommerce Creative Slot}}
promotion_id – {{Ecommerce Promotion ID}}
promotion_name – {{Ecommerce Promotion Name}}
items – {{Ecommerce Items}}
Here,
{{Ecommerce Creative Name}} = ecommerce.creative_name
{{Ecommerce Creative Slot}} = ecommerce.creative_slot
{{Ecommerce Promotion ID}} = ecommerce.promotion_id
{{Ecommerce Promotion Name}} = ecommerce.promotion_name
{{Ecommerce Items}} = ecommerce.items
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: select_promotion
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Measuring Checkout steps in GA4
To measure the first step in a checkout process in GA4, push the ‘begin_checkout’ event and the associated item details to the data layer on the page where the user initiates the checkout process.
This is typically the page where the user clicks a button or link to start the checkout process, such as a “Proceed to Checkout” button on the shopping cart page.
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
items: [{ // List each item in the checkout process.
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: begin_checkout
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: begin_checkout
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking coupons in GA4
To add a coupon to the ‘begin_checkout’ event in GA4, you can include the coupon code at the order or item level within the ‘items’ array.
Adding a Coupon code at the Order Level
To add a coupon code that applies to the entire order, include the ‘coupon’ parameter in the ecommerce object of the ‘begin_checkout’ event:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
coupon: "20OFFTOTAL", // Coupon applied to the whole order
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1
}
]
}
});
Adding a Coupon code at the Item Level
To add a coupon that applies to specific items, include the ‘coupon’ parameter within the relevant item objects in the ‘items’ array:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "begin_checkout",
ecommerce: {
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
price: 1200.00,
item_brand: "BrandX",
item_category: "Electronics",
item_variant: "256GB / Black",
quantity: 1,
coupon: "15OFFLAPTOP" // Coupon applied specifically to this item
}
]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: begin_checkout
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: begin_checkout
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Shipping Information
When a user proceeds to the next step in the checkout process and adds shipping information, push the ‘add_shipping_info’ event and the associated item details to the data layer.
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_shipping_info",
ecommerce: {
currency: "USD",
value: 1200.00, // Optional: Total value of the transaction.
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
item_brand: "BrandX",
item_variant: "256GB / Black",
price: 1200.00,
quantity: 1
}
]
}
});
Use the ‘shipping_tier parameter’ to specify the user’s delivery option, such as “Ground”, “Air”, or “Next-day”:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_shipping_info",
ecommerce: {
currency: "USD",
value: 1200.00, // Optional: Total value of the transaction.
items: [
{
item_id: "SKU_12345",
item_name: "High-Performance Laptop",
item_brand: "BrandX",
item_variant: "256GB / Black",
price: 1200.00,
quantity: 1
}
],
shipping_tier: "Next-day" // Specify the type of shipping option chosen.
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_shipping_info
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
shipping_tier – {{Ecommerce Shipping Tier}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
{{Ecommerce Shipping Tier}} = ecommerce.shipping_tier
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_shipping_info
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking payment information during checkout
Send the ‘ add_payment_info’ event to track when users submit their payment information during checkout.
This event can be enhanced by including the ‘payment_type’ parameter, which specifies the customer’s method of payment.
Here’s how you might implement this in your data layer:
dataLayer.push({ ecommerce: null }); // Clears any previous ecommerce data.
dataLayer.push({
event: "add_payment_info",
ecommerce: {
payment_type: "Credit Card" // Specify the type of payment method used
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: add_payment_info
Event Parameters:
items – {{Ecommerce Items}}
value – {{Ecommerce Value}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
payment_type – {{Ecommerce Payment Type}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
{{Ecommerce Payment Type}} = ecommerce.shipping_tier
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: add_payment_info
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Tracking Purchases in GA4
To measure a purchase in GA4, push the ‘purchase’ event and the associated item details to the data layer on the order confirmation page.
dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
dataLayer.push({
event: "purchase",
ecommerce: {
transaction_id: "T12345",
value: 72.05,
tax: 3.60,
shipping: 5.99,
currency: "USD",
coupon: "SUMMER_SALE",
items: [
{
item_id: "SKU_67890",
item_name: "Wireless Bluetooth Mouse",
affiliation: "Tech Gear Online",
coupon: "TECH20",
discount: 5.00,
index: 0,
item_brand: "LogiTech",
item_category: "Electronics",
item_category2: "Computer Accessories",
item_category3: "Mice",
item_category4: "Wireless",
item_category5: "Bluetooth",
item_list_id: "tech_basics",
item_list_name: "Essential Tech",
item_variant: "black",
location_id: "ChIJRcbZaklDXz4RYlEphFBu5r0",
price: 29.99,
quantity: 2
},
{
item_id: "SKU_67891",
item_name: "Compact Portable Charger",
affiliation: "Tech Gear Online",
coupon: "CHARGE10",
discount: 3.50,
index: 1,
item_brand: "Anker",
item_category: "Electronics",
item_category2: "Power Banks",
item_category3: "Portable",
item_category4: "Battery",
item_category5: "High Capacity",
item_list_id: "travel_gear",
item_list_name: "Travel Essentials",
item_variant: "white",
promotion_id: "P_67890",
promotion_name: "Tech Travel Sale",
price: 45.00,
quantity: 1
}]
}
});
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: purchase
Event Parameters:
items – {{Ecommerce Items}}
transaction_id – {{Ecommerce Transaction ID}}
value – {{Ecommerce Value}}
tax – {{Ecommerce Tax}}
shipping – {{Ecommerce Shipping}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Transaction ID}} = ecommerce.transaction_id
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Tax}} = ecommerce.tax
{{Ecommerce Shipping}} = ecommerce.shipping
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: purchase
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
Missing Revenue in Google Analytics 4?
Sometimes, you may not see revenue data in your GA4 reports and may assume that the e-commerce tracking set-up is not correct.
There is a good possibility that you do not have permission to access revenue-related metrics for the GA4 property.
Ask your administrator to confirm that the following checkbox is not selected for you under Property > Property Access Management > {Your username} > Data restrictions (GA4 properties only)
No Revenue Metrics.
When the ‘No Revenue Metrics’ checkbox is selected for you, ecommerce reports tend not to be accurate for you, and you can not access any of the ‘revenue-related metrics’ in your GA4 reports.
For example, when the ‘No Revenue Metrics’ checkbox is selected for you, the transactions report may appear like the one below with no data for ‘Ecommerce purchase quantity’ and ‘Purchase revenue’ metrics.
Tracking Refunds in GA4
Refund tracking in GA4 can be implemented by pushing the ‘refund’ event into the dataLayer.
The ‘refund’ event must include a transaction ID to be correctly associated with the original purchase.
For a full refund, push the ‘refund’ event with the transaction ID to the data layer:
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object to ensure clean data.
dataLayer.push({
event: "refund",
ecommerce: {
transaction_id: "T67890" // Unique identifier for the transaction being refunded.
// No item details needed for a full transaction refund
}
});
To track a partial refund in GA4 include both the transaction ID and specific item details of the refunded items in the dataLayer.push event.
dataLayer.push({ ecommerce: null }); // Clears the previous ecommerce object.
dataLayer.push({
event: "refund",
ecommerce: {
transaction_id: "T67890", // Unique identifier for the transaction being partially refunded.
items: [{ // Array of items being partially refunded.
item_id: "SKU_67891", // Unique identifier for the item.
price: 29.99, // Price per unit of the item.
quantity: 1 // Number of units being refunded.
}]
}
});
Including detailed item information in GA4’s refund tracking allows for calculating specific metrics like the Item Refund Amount and the adjusted Item Revenue after refunds.
This granularity provides deeper insights into refund patterns by showing which products are most frequently returned and their overall impact on revenue, enabling better inventory and sales strategy adjustments.
Google tag configuration:
Once the above code is pushed to the DataLayer, configure your Google Tag Manager tag like the one below.
Tag Type: GA4 event
Event Name: refund
Event Parameters:
items – {{Ecommerce Items}}
transaction_id – {{Ecommerce Transaction ID}}
value – {{Ecommerce Value}}
tax – {{Ecommerce Tax}}
shipping – {{Ecommerce Shipping}}
currency – {{Ecommerce Currency}}
coupon – {{Ecommerce Coupon}}
Here,
{{Ecommerce Items}} = ecommerce.items
{{Ecommerce Transaction ID}} = ecommerce.transaction_id
{{Ecommerce Value}} = ecommerce.value
{{Ecommerce Tax}} = ecommerce.tax
{{Ecommerce Shipping}} = ecommerce.shipping
{{Ecommerce Currency}} = ecommerce.currency
{{Ecommerce Coupon}} = ecommerce.coupon
Trigger configuration:
Create a trigger with the below configuration:
Trigger Type: Custom Event
Event Name: refund
This trigger fires on: All Custom Events
Your final tag configuration should look like the one below:
If you see negative values for the ‘Purchase revenue’ or ‘Total revenue’ metrics or $0 value for the ‘Gross purchase revenue’ metric in GA4, it could be because of the refund transaction(s).
Both the ‘Purchase revenue’ and ‘Total revenue’ metrics take refunds into account.
In GA4, both the ‘Purchase revenue’ and ‘Total revenue’ metrics take refunds into account (which is created by firing the ‘refund’ event).
However, the ‘Gross purchase revenue’ metric does not take refund into account. But its value would be zero in case of the refund transaction.
So if you see negative values for the ‘Purchase revenue’ or ‘Total revenue’ metrics or $0 value for the ‘Gross purchase revenue’ metric, apply a secondary dimension called ‘Event name’ to check whether the transaction is recorded because of the ‘purchase’ or ‘refund’ event.
Refund is a type of transaction in GA4.
In GA4, a refund is counted as a transaction, and it impacts your total transaction count.
So, not all transactions are purchase events. They could also include refund events.
So, there are two categories of GA4 transactions:
- Purchase transactions.
- Refund transactions.
When reporting on e-commerce data, make sure that you segment the data based on purchases and refunds.
This segmentation allows for a clear distinction between revenue-generating transactions and refunds, providing a more precise picture of your e-commerce performance.
It is also equally important to segment the e-commerce data for web and app by using the ‘Stream name’ dimension if you also use mobile apps in addition to a website.
If you want to report on the total number of refunds and refund amount in GA4 reports, then use the ‘Refunds’ and ‘Refund amount’ metrics:
However, these metrics are not available by default in standard reports. You will have to customize your report to add them.
So, that is how you can set up ecommerce tracking in Google Analytics 4.
Top Implementation Mistakes in GA4 Ecommerce Tracking
Beware of these 7 common implementation mistakes in your GA4 ecommerce tracking:
- Not looking at the ‘Event count per user’ metric’ for ecommerce events.
- Not tracking state changes.
- Not using a throttling function.
- Not using debouncing techniques.
- Not clearing the ecommerce data in the data layer.
- Not including all relevant event parameters with each ecommerce event.
- Not involving client’s web developers/IT team.
Mistake #1: Not looking at the ‘Event count per user’ metric’ for ecommerce events.
It is common to see inflated ecommerce events in a GA4 property because most developers do not set up ecommerce tracking correctly.
A quick way to check for duplicate ecommerce events in GA4 is to look at the ‘Event Count Per user’ metric.
A high event count per user can be a sign of duplicate ecommerce events.
For example, it is very unlikely for a typical user to add payment information 23 times repeatedly.
Mistake #2: Not tracking state changes.
It is common to see inflated ecommerce events in a GA4 property because most developers do not track state changes but rather send duplicate events to GA4.
If a user repeatedly performs an action (e.g., clicking an “add to cart” button multiple times), tracking state changes helps you avoid counting each click as a separate event, which could inflate your ‘add to cart’ metric and provide an inaccurate view of user behaviour.
Consider a scenario where a user is adjusting the quantity of an item in their shopping cart:
Without State Change Tracking:
You might send an ‘add_to_cart’ event whenever the user changes the quantity.
If the user increases the quantity from 1 to 5, one unit at a time, this might result in 5 separate ‘add_to_cart’ events, leading to duplicate events.
With State Change Tracking:
You can send a single custom event, like ‘cart_quantity_updated’, along with parameters that reflect the old and new quantities.
This provides a more accurate view of the user’s actions without creating duplicate events.
Tracking state changes rather than sending duplicate events in GA4 can provide a more accurate representation of user interactions on your website.
Below, I provide a simple example using JavaScript that checks whether an item has already been added to the cart before sending an event to GA4. This example assumes you’re working in a browser environment where session storage is available:
// Function to add item to the cart
function addToCart(itemId, quantity) {
const cartKey = 'userCart';
let cart = JSON.parse(sessionStorage.getItem(cartKey)) || {};
// Check if the item already exists in the cart
if (cart[itemId]) {
// Item exists, update the quantity if different
if (cart[itemId] !== quantity) {
cart[itemId] = quantity;
// Send update to GA4 as a state change
trackEventGA4('update_cart', { itemId: itemId, quantity: quantity });
}
} else {
// Item does not exist, add new item
cart[itemId] = quantity;
// Send add to cart event to GA4
trackEventGA4('add_to_cart', { itemId: itemId, quantity: quantity });
}
// Update the cart in session storage
sessionStorage.setItem(cartKey, JSON.stringify(cart));
}
// Function to track events in GA4
function trackEventGA4(eventName, eventParams) {
console.log(`Tracking event: ${eventName}`, eventParams); // Placeholder for GA4 tracking code
// gtag('event', eventName, eventParams); Uncomment this and configure gtag for your GA4
}
// Example usage
document.getElementById('addToCartButton').addEventListener('click', function() {
const itemId = this.getAttribute('data-item-id');
const quantity = parseInt(this.getAttribute('data-quantity'), 10);
addToCart(itemId, quantity);
});
You can use a data layer to manage and track state changes effectively.
The data layer can hold information about the current state and can be used to trigger specific tags based on changes to that state.
// Initialize the data layer object
window.dataLayer = window.dataLayer || [];
// Function to update data layer when a product is added to the cart
function updateDataLayer(eventAction, product) {
window.dataLayer.push({
event: eventAction,
ecommerce: {
currency: 'USD',
items: [{
item_id: product.id,
item_name: product.name,
item_category: product.category,
price: product.price,
quantity: product.quantity,
item_variant: product.variant || 'default',
item_list_name: product.listName || 'Search Results',
item_list_id: product.listId || 'SR123',
index: product.index || 0
}]
}
});
}
// Example product data
const exampleProduct = {
id: 'P12345',
name: 'Awesome Widget',
category: 'Gadgets',
price: 19.99,
quantity: 1
};
// Simulate adding an item to the cart
updateDataLayer('add_to_cart', exampleProduct);
GA4 allows for custom parameters with events, enabling you to send additional information about the state change (e.g., the old and new quantities).
Let’s assume you want to track how users update the item quantities in their shopping carts.
Here’s how you could structure the event data with custom parameters to capture both the old and new quantities:
// Function to track changes in the item quantity in the shopping cart
function trackQuantityChange(itemId, oldQuantity, newQuantity) {
// Send the event to GA4 with custom parameters
gtag('event', 'update_quantity', {
'item_id': itemId,
'old_quantity': oldQuantity,
'new_quantity': newQuantity
});
}
// Example usage of the function
trackQuantityChange('P12345', 1, 3);
Your ecommerce tracking in GA4 is unlikely to be ever accurate if you do not track state changes.
Mistake #3: Not using a throttling function.
A throttling function is another good method to prevent sending duplicate ecommerce events to GA4.
For example, a throttling function ensures that the ‘purchase’ event is not fired more than once when the order confirmation page reloads by a user. This would prevent duplicate ‘purchase’ events.
Following is an example of how you could implement a simple throttling function in JavaScript which ensures that a ‘purchase’ event isn’t sent to GA4 more than once within a specified time frame, such as when a user may accidentally or intentionally reload an order confirmation page:
// Throttle function to limit how often a callback can be executed
function throttle(callback, limit) {
var waiting = false; // Initially, no throttle is being applied
return function () {
if (!waiting) {
callback.apply(this, arguments);
waiting = true; // Throttle subsequent calls
setTimeout(function () {
waiting = false; // After a period, allow future calls
}, limit);
}
};
}
// Function to send a purchase event to GA4
function trackPurchaseEvent() {
console.log("Purchase event tracked"); // Placeholder for actual tracking code
// gtag('event', 'purchase', { /* event parameters */ });
}
// Throttled version of the trackPurchaseEvent function
const throttledTrackPurchase = throttle(trackPurchaseEvent, 5000); // Only allow a purchase event every 5 seconds
// Example of how to use the throttled function
document.getElementById('confirmButton').addEventListener('click', throttledTrackPurchase);
Your ecommerce tracking in GA4 is unlikely to be ever accurate if you do not use a throttling function.
Mistake #4: Not using debouncing techniques.
Implementing debouncing techniques can effectively prevent rapid, repeated actions from causing duplication in your ecommerce tracking.
Debouncing ensures that a function does not execute until a certain amount of time has passed since the last time the function was executed.
This technique can be useful for preventing rapid, repeated clicks, say on a ‘Complete Order’ button, from causing duplicate ‘purchase’ events.
The following example shows how to implement a debounce function in JavaScript to prevent duplicate purchase events from being fired due to repeated clicks on a ‘complete order’ button:
// Debounce function to limit how often a function can run
function debounce(func, delay) {
let debounceTimer;
return function() {
const context = this;
const args = arguments;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => func.apply(context, args), delay);
};
}
// Function to send a purchase event to GA4
function trackPurchaseEvent() {
console.log("Purchase event tracked"); // Placeholder for actual tracking code
// gtag('event', 'purchase', { /* event parameters here */ });
}
// Debounced version of the trackPurchaseEvent function
const debouncedTrackPurchase = debounce(trackPurchaseEvent, 2000); // 2000 milliseconds delay
// Setup event listener for the complete order button
document.getElementById('completeOrderButton').addEventListener('click', debouncedTrackPurchase);
Difference between Debouncing and Throttling.
Debouncing delays the function execution until there is a pause in the event triggering the function. Whereas, throttling controls the execution frequency to a fixed rate, ensuring the function executes at regular intervals.
Mistake #5: Not clearing the ecommerce data in the data layer.
Always clear the ecommerce data in the data layer before pushing a new transaction event in GA4.
dataLayer.push({ ‘ecommerce’: null }); // Clear previous data
By clearing past data, you ensure the new transaction event reflects the current state, preventing contamination from previous actions like adding or removing items.
Mixed data points from different transactions can cause errors in tracking and reporting.
Example:
Suppose a customer adds a laptop-x1 and then later removes it, only to add a different model (laptop-y2) to their cart.
If the ecommerce data isn’t cleared before the new transaction data is pushed, both laptops might incorrectly appear in the transaction details, leading to errors in sales tracking:
// Initial incorrect state in the dataLayer
dataLayer = {
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-x1"} // From step 1 (incorrect)
]
}
}
};
// When Laptop Y2 is added
dataLayer.push({
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-x1"}, // Still present (incorrect)
{"id": "laptop-y2"} // Newly added (correct)
]
}
}
});
When adding a new item (laptop-y2) after clearing the data, ensure that only the relevant, current items are reflected in the data layer.
dataLayer.push({ 'ecommerce': null }); // Clears the previous ecommerce data for accuracy
dataLayer.push({
"ecommerce": {
"cart": {
"items": [
{"id": "laptop-y2"} // Correctly reflects the current cart content
]
}
}
});
This action keeps the cart and inventory data accurate.
Mistake #6: Not including all relevant event parameters with each ecommerce event.
Each e-commerce event in GA4 requires specific event parameters to be included.
If these event parameters are missing or incorrectly configured, GA4 will display “(not set)” as a placeholder value.
For example,
If the ‘item_name’ parameter is not included in the ‘add_to_cart’ event, the item name will appear as “(not set)” in the e-commerce reports.
Mistake #7: Not involving client’s web developers/IT team.
Are you trying to install GA4 ecommerce tracking all by yourself?
Q. Can you code a server-side language (like PHP)?
Q. Do you know how to programmatically query a database?
Q. Do you understand the Google Analytics development environment like the back of your hand?
Q. Do you understand your client’s development environment/database?
If the answer to any of the above questions is ‘NO’ then you won’t be able to install ecommerce tracking all by yourself.
Often, marketers who attempt to install ecommerce tracking have developed a false belief that they can set up all types of tracking by themselves through GTM.
That they can somehow become independent from the IT/Web developer.
They overestimate their abilities because Google has been preaching to them for years that GTM makes you independent of web developers.
Even when you have adequate knowledge of HTML, DOM, and JavaScript, you would still need the help of the client’s web developers/IT to add server-side code to your data layers or to query their database for you.
Without adding server-side code to GTM data layers, you can not implement ecommerce tracking in GA4.
Monetization Reports in Google Analytics 4
Once you have set up ecommerce tracking in GA4, you can access the various ecommerce reports in your GA4 property under ‘Monetization’.
In the context of GA4, the e-commerce reports are known as the Monetization reports.
The following monetization reports are available in GA4:
- Monetization Overview Report.
- Ecommerce Purchases Report.
- In-app purchases Report.
- Publisher ads Report.
- Promotions Report.
- User Purchase Journey Report.
- Order Coupon Report.
- Item list Report.
- Checkout Journey Report.
Update: New dimensions and metrics for ecommerce in GA4
GA4 has introduced new dimensions and metrics for ecommerce.
It also now provides an event-scoped and item-scoped version of ecommerce metrics and dimensions.
Event-scoped metrics measure the number of times an ecommerce event was triggered on your website/app.
For example,
‘Add to carts‘ is an event-scoped metric that measures the number of times users add items to a shopping cart.
This metric is populated by sending the add_to_cart event.
Item-scoped metrics measure the number of items users interacted with on your website/app.
For example,
‘Items added to cart‘ is an item-scoped metric that measures the number of items added to the cart.
This metric is populated by sending an items array with the add_to_cart event.
Just like GA4 ecommerce metrics, there are event-scoped and item-scoped dimensions.
“Item-scoped and event-scoped dimensions and metrics are incompatible with one another. Any time you use an item-scoped dimension, you must select an item-scoped metric rather than the equivalent event-scoped metric. The same applies to event-scoped dimensions and metrics.” – Google
The new ecommerce dimensions and metrics are found in exploration reports and the data API:
1) Item affiliation – The name or code of the affiliate associated with an item you sell.
2) Item variant – Like small, medium, large.
3) Items added to cart – number of items added to the cart.
4) Items checked out – number of items that were in the cart during checkout.
5) Items clicked in list – number of items clicked in a product list.
6) Items clicked in promotion – number of items clicked in a promotion.
7) Items viewed – number of items viewed.
8) Items viewed in list – number of items viewed in a product list.
9) Items viewed in promotion – number of items viewed in a promotion.
10) Shipping amount – the shipping amount associated with a transaction.
11) Shipping tier – different levels of shipping services offered by a company like standard, expedited, one-day delivery etc.
12) Tax amount – the tax amount associated with a transaction.
GA4 renamed the following ecommerce metrics:
- Add to carts (previously called Add-to-carts)
- Item-list click events (previously called Item list clicks)
- Item-list view events (previously called Item list views)
- Item view events (previously called Item views)
- Items purchased (previously called Item purchase quantity)
- Promotion clicks (previously called Item promotion clicks)
- Promotion views (previously called Item promotion views)
FAQ: We see a discrepancy in Sales in GA4 compared to UA (UA is closer to Shopify data, which is the most accurate). How do we fix this?
For purchase data between UA (Universal Analytics) and GA4, we are able to consistently match 90% or higher.
On one of the websites, we matched up to 98% of the purchase data between Universal Analytics and GA4.
Up to 10% of data discrepancy between Universal Analytics and GA4 purchase data is normal, as Universal Analytics and GA4 use different measurement models, and then there are other factors involved (like data threshold, data retention, data sampling, cardinality etc.).
However, if the data discrepancy is more than 20%, something is most likely wrong with your GA4 ecommerce tracking setup.
The more marketing channels you use to generate sales, the harder it becomes to fix discrepancies between Universal Analytics and GA4 purchase data or data discrepancies between GA4 and Shopping Cart purchase data.
To fix data discrepancies, the first step is to compare your purchase data by marketing channels between Universal Analytics and GA4 to identify patterns and potential causes for the discrepancies.
Suppose you concluded that Universal Analytics reported $20k in sales from Facebook ads in the last month, but GA4 reported only $9k in sales from Facebook ads during the same time period.
The next step is to figure out why GA4 is underreporting sales from Facebook ads.
Is it because of UTM parameters, data threshold, data sampling, recent IOS update or something else?
Facebook is often the channel that is the hardest to track in generating sales because of IOS 14.5+ updates.
Use the Facebook Conversion API (CAPI) along with your Facebook pixel to get more conversion data from Facebook ads.
If you can’t figure out why GA4 is underreporting sales from Facebook ads, compare the Universal Analytics purchase data with GA4 BigQuery export purchase data.
The GA4 BigQuery export data does not suffer from data sampling, data thresholding or cardinality limits issues.
So if you see a lot of data discrepancy between GA4 BigQuery export data and the data from the GA4 UI or data API, it means one or all the following factors result in underreporting: data threshold, data retention, data sampling, cardinality etc.
You have room for improvement if you don’t see a lot of data discrepancy between GA4 BigQuery export data and the data from the GA4 UI or data API.
Bear in mind that due to enhanced ecommerce tracking, Universal Analytics can track a lot more ecommerce data than GA4. So it is not really apple to apple comparison.
While setting up ecommerce tracking in GA4, build a mechanism to handle the following by adjusting the sales data to reflect the changes: cancelled orders, unfulfilled orders, test orders, promotions (promo codes, discounts) and refunds (partial or full).
If your website supports multiple currencies during checkout, this could create data discrepancy issues between GA4 and your shopping cart. Wherever possible, use one currency for checkout.
Finally, choose a shopping cart that fully supports GA4.
Universal Analytics has been around for decades. So many shopping carts and plugins fully support Universal Analytics.
But this is not the case with GA4 which could result in the underreporting of sales data or other data discrepancies.
How to find duplicate transactions in GA4?
Two or more transactions with the same transaction ID are called duplicate transactions.
GA4 automatically de-duplicates transactions with the same transaction ID from the same user.
However, if the same transaction ID is used for different users, such transactions are not automatically de-duplicated by GA4.
You will first need to find duplicate transactions in your GA4 property and then ask your developer to fix them.
Look at the ‘Purchases’ column of your exploration report. They should all be 1.
If you find any value greater than 1, you have got duplicate transaction issue.
For more details on GA4 duplicate transactions, check out this article: Duplicate Transactions (orders) in Google Analytics 4.
Ecommerce Conversion Rate in Google Analytics 4 (GA4)
Unlike Universal Analytics, GA4 does not provide e-commerce conversion rate metric. It is missing for no apparent reason. However, there is a workaround.
You can use the ‘Session Conversion Rate‘ metric as an e-commerce conversion rate metric via the exploration report.
To learn more, check out this article: GA4 Ecommerce Conversion Rate – How to find and use it.
Other articles on Google Analytics Ecommerce
- Google Analytics Ecommerce Tracking Tutorial
- Enhanced Ecommerce Tracking in Google Analytics – Tutorial
- Set up Enhanced Ecommerce Tracking in Google Analytics
- Using Enhanced Ecommerce segments for Remarketing in Google Analytics
- Using Cohort Analysis & Enhanced Ecommerce to Understand User Behavior
- Duplicate Transactions (orders) in Google Analytics
- Enhanced Ecommerce Tracking via Google Tag Manager
- Ecommerce Tracking Google Tag Manager (GTM) – Tutorial
- Shopify Enhanced Ecommerce Tracking in Google Analytics – Tutorial
- Why Google Analytics and Shopping Cart Sales data don’t match and how to fix it
- How to remove / modify Google Analytics ecommerce transaction in one click
- Tracking Google Analytics Paypal Referral and other payment gateways
- Subscription & Recurring Revenue Analytics in Google Analytics
- Understanding Google Analytics Product Data Import
- Shopping Cart Analytics Tutorial
- Learn To Read E-Commerce Reports In Google Analytics
- Dealing with Google Analytics Refund – Reverse Transaction
- How to reverse transactions in Google Analytics for gtag.js and analytics.js
- How to Fix Missing Ecommerce Data in Google Analytics
My best selling books on Digital Analytics and Conversion Optimization
Maths and Stats for Web Analytics and Conversion Optimization
This expert guide will teach you how to leverage the knowledge of maths and statistics in order to accurately interpret data and take actions, which can quickly improve the bottom-line of your online business.
Master the Essentials of Email Marketing Analytics
This book focuses solely on the ‘analytics’ that power your email marketing optimization program and will help you dramatically reduce your cost per acquisition and increase marketing ROI by tracking the performance of the various KPIs and metrics used for email marketing.
Attribution Modelling in Google Analytics and BeyondSECOND EDITION OUT NOW!
Attribution modelling is the process of determining the most effective marketing channels for investment. This book has been written to help you implement attribution modelling. It will teach you how to leverage the knowledge of attribution modelling in order to allocate marketing budget and understand buying behaviour.
Attribution Modelling in Google Ads and Facebook
This book has been written to help you implement attribution modelling in Google Ads (Google AdWords) and Facebook. It will teach you, how to leverage the knowledge of attribution modelling in order to understand the customer purchasing journey and determine the most effective marketing channels for investment.