How-to

How to Set Up Google Tag Manager on Shopify (Storefront + Checkout)

How to Set Up Google Tag Manager on Shopify (Storefront + Checkout)the storefrontStorefrontGTM installedthe checkout (sandboxed)Checkoutsandbox — no DOMcustom pixelCustomer Events → GA4product_viewedview_itemcheckout_startedbegin_checkoutcheckout_completedpurchase$129

"Put Google Tag Manager on Shopify" sounds like one task. It's really two, and the second one is where almost everyone gets stuck. Shopify's checkout runs in a locked-down sandbox that the ordinary GTM snippet can't reach, so you need a different mechanism there: Customer Events with GTM running inside a custom pixel. This guide walks both halves end to end.

Why Shopify GTM is two jobs, not one

On a normal site you paste the GTM snippet into the page and you're done, the container can read the DOM, watch clicks, and see every dataLayer push. Shopify's checkout doesn't work that way. Modern stores run Checkout Extensibility, where the checkout and Thank you pages are owned by Shopify and isolated from your theme.

Storefront (the easy half)

  • GTM snippet lives on the page
  • Container reads the DOM and dataLayer
  • Preview / Tag Assistant connects directly

Checkout (the hard half)

  • Sandboxed by Checkout Extensibility
  • No access to the page DOM or window
  • You subscribe to Customer Events instead

Part 1: GTM on the Shopify storefront

For the storefront (home, collection and product pages), GTM installs the normal way. The cleanest route on modern themes is the theme.liquid head, or a trusted app, avoid pasting it in two places, which is a common cause of double-loaded containers.

  1. In GTM, open Admin → Install Google Tag Manager and copy both snippets.
  2. Add the <head> snippet high in theme.liquid, and the <body> snippet right after the opening <body> tag.
  3. Publish, open the storefront in Preview, and confirm the container connects.

Heads up

The storefront snippet does not reach the checkout. If you stop here, you'll track product views and add-to-carts but lose the purchase, the event that matters most.

Part 2: GTM on the Shopify checkout (custom pixel)

To collect data in the sandboxed checkout, Shopify gives you Customer Events (the Web Pixels API). Your code runs in a sandbox that cannot touch the storefront DOM or the page's real window. Instead of reading the page, you subscribe to a fixed set of events Shopify emits and forward them.

First, confirm you can actually use it

  • Checkout Extensibility is on. On a store still using legacy checkout.liquid, custom pixels go silent through checkout. Verify this first.
  • Admin access to Settings → Customer events. If you can't see that page, it's a permissions problem, not a code one.
  • Protected customer data approval: only needed for PII (email, phone, name, address). Order id, totals, currency and line items flow without it.

Run GTM inside the pixel

The supported pattern is to load GTM inside a custom pixel and feed it a dataLayer you build yourself from Customer Events. Go to Settings → Customer events → Add custom pixel, then:

1Copy GTM install code2Strip the <script> tags3Paste into the pixel4Subscribe → dataLayer.push
// Define your own dataLayer inside the sandbox first
window.dataLayer = window.dataLayer || [];

// GTM loader, the install snippet with the <script> tags removed
(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');

Then subscribe to the events you care about and push clean objects whose event key your GTM triggers will match:

analytics.subscribe("checkout_completed", (event) => {
  const c = event.data?.checkout;
  window.dataLayer.push({
    event: "checkout_completed",
    orderId: c?.order?.id,
    currency: c?.currencyCode,
    value: c?.totalPrice?.amount,
    shipping: c?.shippingLine?.price?.amount,
    tax: c?.totalTax?.amount,
    items: (c?.lineItems || []).map((li) => ({
      item_id: li.variant?.sku || li.variant?.product?.id,
      item_name: li.title,
      price: li.variant?.price?.amount,
      quantity: li.quantity,
    })),
  });
});

Critical rule

An empty container loaded in the pixel transfers nothing. A tag and trigger must exist in GTM for data to flow. And the sandbox has no shared dataLayer, carry every value you need on each push.

Practice this on a real container

The Shopify checkout_completed lesson simulates exactly what a custom pixel pushes (same fields, same trigger name), so you can build the GTM half (variables, Custom Event trigger, GA4 purchase tag) without a live store.

Practice the Shopify purchase →

Part 3: map Shopify events to GA4

Follow Shopify's canonical mapping, each event maps to a GA4 event, each field to a GA4 parameter:

  • product_viewedview_item
  • product_added_to_cartadd_to_cart
  • checkout_startedbegin_checkout
  • payment_info_submittedadd_payment_info
  • checkout_completedpurchase

Most fields are straight renames (order.id → transaction_id, totalPrice.amount → value, currencyCode → currency). The one exception is lineItems, which you reshape into GA4's items array (as in the code above).

Part 4: test it (Preview won't reach checkout)

This surprises everyone: GTM Preview / Tag Assistant cannot connect to the checkout , it can't see into the pixel sandbox where your GTM and dataLayer live. So you test a different way:

  • Use the Shopify Pixel Helper to confirm events reach the sandbox without errors.
  • Open DevTools Console, switch the JavaScript context (the frame dropdown) to the pixel sandbox, and inspect window.dataLayer there.
  • Place a real test order, a 100%-off discount code is the usual trick, and watch the checkout_completed push appear.

The gotchas that corrupt Shopify data

  • Double-counted purchases. The classic: an app pixel and your custom pixel both send purchase, or native Shopify GA4 plus your own GA4 tag. Pick one source of truth and reconcile GA4 against Shopify's order count.
  • Empty PII fields. Email/phone/address stay blank without protected-data approval.
  • Upsell flows move the event. With post-purchase offers, checkout_completed fires on the first upsell page, not the Thank you page.
  • Legacy checkout. Still on checkout.liquid? The pixel won't fire through checkout at all.

Now go practice it

Reading sticks when you do it. These hands-on lessons load your own GTM container and let you debug in Tag Assistant.

Frequently asked questions

How do I add Google Tag Manager to Shopify?

In two parts. For the storefront, paste the GTM snippets into theme.liquid (head + body) the normal way. For the sandboxed checkout, go to Settings → Customer events → Add custom pixel, load GTM inside the pixel with the script tags stripped, define your own window.dataLayer, then subscribe to Customer Events and push them so GTM triggers can fire.

Why doesn't the normal GTM snippet work on Shopify checkout?

Modern Shopify stores use Checkout Extensibility, which isolates the checkout and Thank you pages in a sandbox. The ordinary GTM snippet can't read that page's DOM or window, so it can't track checkout. Shopify's supported route is Customer Events (the Web Pixels API) via a custom pixel.

How do I track a Shopify purchase in GA4?

Subscribe to the checkout_completed event in your custom pixel and push order id, value, currency, shipping, tax and a reshaped items array to the dataLayer. In GTM, add a Data Layer Variable per field, a Custom Event trigger named checkout_completed, and a GA4 purchase tag mapping transaction_id, value, currency and items.

Why can't I test Shopify checkout in GTM Preview?

GTM Preview / Tag Assistant cannot connect into the pixel sandbox where your GTM and dataLayer run on checkout. Test instead with the Shopify Pixel Helper, by switching the DevTools console to the pixel sandbox frame, and by placing a real test order with a 100%-off discount code.

Why are my Shopify purchases counted twice in GA4?

Usually two integrations both send the purchase, for example an app pixel plus your custom pixel, or native Shopify GA4 plus your own GA4 tag. Keep a single source of truth for the purchase event and reconcile GA4 against Shopify's order count.

Related posts

About the author

Nathan Gage
Nathan Gage

Analytics & Tag Management Consultant

Nathan Gage got his start in marketing through Google Tag Manager. Seeing how tracking customer behavior could turn raw clicks into insight you can actually act on is what pulled him into the field. Since then he has worked both full time and as a consultant with 15 marketing agencies, supporting brands that spend anywhere from a thousand dollars a month to over a million. Along the way he built a multi-touch attribution app, and he created The Happy Tagger so anyone can practice GTM, GA4 and server-side tracking on a real container instead of a production site.