How-to
How to Set Up Google Tag Manager on Shopify (Storefront + Checkout)
"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.
- In GTM, open Admin → Install Google Tag Manager and copy both snippets.
- Add the
<head>snippet high intheme.liquid, and the<body>snippet right after the opening<body>tag. - Publish, open the storefront in Preview, and confirm the container connects.
Heads up
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:
// 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
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_viewed→view_itemproduct_added_to_cart→add_to_cartcheckout_started→begin_checkoutpayment_info_submitted→add_payment_infocheckout_completed→purchase
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.dataLayerthere. - Place a real test order, a 100%-off discount code is the usual trick, and watch the
checkout_completedpush 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_completedfires 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
How-to
How to Track Form Submissions in Google Tag Manager (Without Losing Conversions)
Form submissions are leads, and the easiest tracking to get wrong. Three reliable methods, plus the redirect gotcha that silently loses conversions and how to beat it.
Read →How-to
How to Set Up GA4 Ecommerce Tracking with Google Tag Manager
GA4 ecommerce is one pattern repeated across a few events. Walk the full funnel in GTM (from the base tag to a deduplicated purchase with revenue) with copy-paste dataLayer examples.
Read →How-to
How to Set Up Google Ads Conversion Tracking with GTM
Google Ads only optimizes toward conversions it can see. The reliable GTM setup (Conversion Linker plus the conversion tag, with value and dedup), and the mistakes that quietly cost you.
Read →About the author

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.