Shopify 14 min read

Shopify Analytics: GA4 + GTM Integration Guide

How to install Google Tag Manager on Shopify, build the e-commerce data layer for GA4, and correctly track purchase events on the checkout confirmation page.

A
Aumlytics Team
·

Shopify analytics tracking has always been tricky. The platform controls the checkout flow, which means the thank-you page — the most valuable page on your entire store — lives on a different domain (checkout.shopify.com) and blocks most tag managers. This guide shows you exactly how to do it right.

Why Shopify’s Built-in Analytics Isn’t Enough

Shopify’s native analytics dashboard tells you revenue and sessions. It can’t tell you:

  • Which marketing channel drove each purchase (without UTM parameters)
  • How users behaved before they added to cart
  • Where users dropped off in your checkout funnel
  • Which product categories drive the most LTV

For those answers, you need GA4. And for clean, maintainable GA4 implementation, you need GTM.

Two Integration Approaches

Install GTM in your Shopify theme and push data layer events from Liquid templates. This works for everything except the hosted checkout.

Option B: Shopify Web Pixels API

A newer sandboxed JavaScript approach that works within Shopify’s checkout. More complex to build but works end-to-end. Best for stores on Shopify Plus or where checkout customization is already needed.

This guide covers Option A, which works for 95% of stores.

Step 1: Install GTM on Shopify

In your Shopify Admin, go to Online Store → Themes → Edit code.

Open theme.liquid (or layout/theme.liquid).

Add the GTM snippet inside <head> (after any existing scripts):

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

Add the GTM noscript directly after the opening <body> tag:

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Replace GTM-XXXXXXX with your actual GTM container ID.

Step 2: Build the Data Layer in Liquid

Shopify doesn’t push a native data layer — you have to build it using Liquid variables.

Create a new snippet file: Snippets → Add a new snippet → name it gtm-datalayer.liquid

<script>
  window.dataLayer = window.dataLayer || [];

  {% if template == 'product' %}
  window.dataLayer.push({
    event: 'view_item',
    ecommerce: {
      currency: {{ shop.currency | json }},
      value: {{ product.selected_or_first_available_variant.price | divided_by: 100.0 }},
      items: [{
        item_id: {{ product.selected_or_first_available_variant.sku | json }},
        item_name: {{ product.title | json }},
        item_category: {{ product.type | json }},
        item_brand: {{ product.vendor | json }},
        price: {{ product.selected_or_first_available_variant.price | divided_by: 100.0 }},
        quantity: 1
      }]
    }
  });
  {% endif %}

  {% if template == 'cart' %}
  window.dataLayer.push({
    event: 'view_cart',
    ecommerce: {
      currency: {{ shop.currency | json }},
      value: {{ cart.total_price | divided_by: 100.0 }},
      items: [
        {% for item in cart.items %}
        {
          item_id: {{ item.variant.sku | json }},
          item_name: {{ item.product.title | json }},
          item_variant: {{ item.variant.title | json }},
          item_category: {{ item.product.type | json }},
          price: {{ item.price | divided_by: 100.0 }},
          quantity: {{ item.quantity }}
        }{% unless forloop.last %},{% endunless %}
        {% endfor %}
      ]
    }
  });
  {% endif %}
</script>

Include this snippet in theme.liquid inside <head>, after your GTM snippet:

{% render 'gtm-datalayer' %}

Step 3: Track Add to Cart

Add-to-cart tracking requires JavaScript because the action happens asynchronously. Add this to your product template or a global JS file:

// Listen for Shopify's cart update events
document.addEventListener('click', function(e) {
  const addToCartBtn = e.target.closest('[data-action="add-to-cart"], .add-to-cart, #AddToCart');
  if (!addToCartBtn) return;

  // Get product data from the button's data attributes (you may need to add these in your theme)
  const productData = {
    item_id: addToCartBtn.dataset.sku || addToCartBtn.dataset.variantId,
    item_name: addToCartBtn.dataset.productTitle,
    price: parseFloat(addToCartBtn.dataset.price) / 100,
    quantity: parseInt(document.querySelector('[name="quantity"]')?.value || 1)
  };

  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push({
    event: 'add_to_cart',
    ecommerce: {
      currency: window.Shopify?.currency?.active || 'USD',
      value: productData.price * productData.quantity,
      items: [productData]
    }
  });
});

Step 4: The Checkout Tracking Problem

This is where most Shopify implementations fail. Shopify’s checkout is hosted on checkout.shopify.com — a separate domain that you cannot inject arbitrary JavaScript into (unless you’re on Shopify Plus).

For standard Shopify plans: Use the Additional Scripts field in Shopify Admin → Settings → Checkout → Order status page. This is the order confirmation (thank-you) page.

Add this to the Additional Scripts field:

{% if first_time_accessed %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
  event: 'purchase',
  ecommerce: {
    transaction_id: '{{ order.order_number }}',
    value: {{ order.total_price | divided_by: 100.0 }},
    tax: {{ order.tax_price | divided_by: 100.0 }},
    shipping: {{ order.shipping_price | divided_by: 100.0 }},
    currency: '{{ order.currency }}',
    coupon: '{{ order.discount_code }}',
    items: [
      {% for line_item in order.line_items %}
      {
        item_id: {{ line_item.sku | json }},
        item_name: {{ line_item.title | json }},
        item_variant: {{ line_item.variant.title | json }},
        item_category: {{ line_item.product.type | json }},
        price: {{ line_item.price | divided_by: 100.0 }},
        quantity: {{ line_item.quantity }}
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ]
  }
});
</script>

<!-- GTM snippet for the checkout thank-you page -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
{% endif %}

The {% if first_time_accessed %} Liquid condition ensures the purchase event fires only once, even if the customer refreshes the thank-you page.

Step 5: Testing Your Shopify GTM Setup

  1. Enable GTM Preview Mode — connect to your Shopify storefront URL (not checkout.shopify.com)
  2. Browse to a product page — verify view_item fires with correct product data
  3. Add to cart — verify add_to_cart fires
  4. Complete a test order (use Shopify’s test payment gateway) — verify purchase fires on the thank-you page with the correct transaction_id and value

Debugging the checkout page: Since the checkout lives on a separate domain, Tag Assistant won’t connect automatically. Use console.log(window.dataLayer) in the Additional Scripts field to inspect the pushed data.

Common Shopify GTM Issues

GTM fires but no data in GA4: Check that your GA4 configuration tag fires on the checkout thank-you page domain. The “Your Domain” restriction in the tag configuration will block it.

Purchase value is wrong: Shopify prices in price fields are in cents (e.g., 4999 = $49.99). Always divide by 100.

Duplicate purchases: Remove any Shopify native GA4 integration if you’re managing tracking via GTM. Having both active double-counts revenue.


Our team specializes in Shopify + GA4 tracking setups, including complex multi-currency stores and Shopify Plus checkout extensibility. Contact us to audit your current setup or build it from scratch.

#shopify#ga4#gtm#ecommerce-tracking#checkout#data-layer

Want This Implemented Correctly?

Let our team apply these concepts to your specific setup — with QA validation and 30 days of support.