There are five ways to set up Google Tag Manager on Shopify today: paste GTM into your theme, load it in a custom pixel, combine the two, install an app such as Addingwell or Stape, or add server-side GTM on top of any of them. They don’t track the same things. The theme can’t see the checkout, the pixel can’t see your pages’ content, and the wrong combination counts every purchase twice. This guide explains each option, with the code, so you can choose the right GTM setup for your Shopify store and check that it works.
Short version: if you want GTM without code, use the Addingwell or Stape app. If you want full control, put GTM in theme.liquid for your store pages and in a custom pixel for the checkout only. In both cases, make sure each event is sent from one place.
What changed: why old GTM tutorials no longer work
For years, installing GTM on Shopify meant pasting the container code into theme.liquid, then adding it again in checkout.liquid (Shopify Plus) or in the Additional scripts box for the thank-you page. Purchases were tracked with a dataLayer push on the order status page.
That’s gone. Between 2024 and 2026, Shopify retired checkout.liquid and the Additional scripts box in stages, Plus stores first, then all stores, as part of Checkout Extensibility. The checkout no longer runs your theme, and it doesn’t accept your scripts. The only supported way to run tracking code in the checkout, including the thank-you page, is a pixel in Settings → Customer events.
So any GTM setup on Shopify now has two parts: your store pages (home, collections, products, cart), where your theme runs, and the checkout, where only pixels run. Every option below is a different way to cover both.
The five options at a glance
| Option | Store pages | Checkout and purchase | GTM Preview mode | Skills needed | Best for |
|---|---|---|---|---|---|
1. GTM in theme.liquid only | Yes, full access | No | Works | Low | Non-ecommerce tags only |
| 2. GTM in a custom pixel only | Yes, through Shopify events | Yes | Doesn’t work | High | Standard ecommerce tracking, no page interactions |
| 3. Theme + custom pixel (hybrid) | Yes, full access | Yes | Store pages only | High | Full control, custom events, agencies |
| 4. An app (Addingwell, Stape, others) | Yes | Yes | Store pages only | Low to medium | Most stores |
| 5. Server-side GTM on top | Yes | Yes, plus order webhooks | Server container has its own | Medium to high | Stores running paid ads |
None of these needs Shopify Plus. Customer events and custom pixels are available on every plan.
Before you start
- Create a GTM web container at tagmanager.google.com (Admin → Create container → Web) and note its ID,
GTM-XXXXXXX. - List what already tracks your store. Open Settings → Customer events and Sales channels: the Google & YouTube app, the Facebook & Instagram app, TikTok, Pinterest and other apps may already send purchases. Check your theme code for old GTM or gtag snippets too. Anything that sends the same event as GTM will create duplicates.
- Decide where consent comes from. Your cookie banner must work with Shopify’s Customer Privacy API, or the checkout won’t know what the visitor accepted. See Consent Mode v2 on Shopify with the Customer Privacy API.
- Install the Shopify Pixel Helper Chrome extension, available from the Customer events page. It’s the only practical way to see what a custom pixel does.
Option 1: GTM in theme.liquid
This is the classic installation, and still the right one for your store pages.
- In Shopify, go to Online Store → Themes, click the … button next to your live theme, then Edit code.
- Open
layout/theme.liquid. - Paste the first GTM snippet as high as possible in the
<head>:
<!-- 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 -->
- Paste the
<noscript>snippet right after the opening<body>tag:
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
- Save, then open your store with GTM’s Preview button to check that the container loads.
What you get: GTM runs on your real pages, with full access to the page. Preview mode works, click and form triggers work, scroll depth works, and page_location and the referrer are correct.
What you don’t get:
- No checkout. GTM never loads on the checkout or the thank-you page, so there is no
begin_checkout, noadd_payment_infoand nopurchase. - No ecommerce dataLayer. Shopify doesn’t push
view_itemoradd_to_cartinto the dataLayer for you. You have to build them in Liquid and JavaScript, including add to carts made with AJAX in a cart drawer. - It belongs to one theme. If you switch or duplicate your theme, the code doesn’t follow unless you copy it.
On its own, this option suits only stores that use GTM for non-ecommerce tags: a chat widget, a heatmap tool, a lead form. For ecommerce tracking, it has to be combined with a pixel.
Option 2: GTM in a custom pixel
This is the method in Shopify’s own GTM tutorial. GTM is loaded inside a custom pixel, and the pixel turns Shopify’s standard events into dataLayer events.
- Go to Settings → Customer events and click Add custom pixel.
- Give it a name, for example “GTM”, and choose its customer privacy settings.
- Paste the code: the GTM loader, then one
analytics.subscribeper Shopify event you want to send. - Click Save, then Connect. The pixel runs only once it’s connected.
The pixel can subscribe to every standard event: page_viewed, product_viewed, collection_viewed, search_submitted, product_added_to_cart, cart_viewed, checkout_started, checkout_contact_info_submitted, checkout_address_info_submitted, checkout_shipping_info_submitted, payment_info_submitted and checkout_completed. That covers the full GA4 ecommerce funnel, from the first page to the purchase, without touching your theme. The complete code is in building a full ecommerce dataLayer from a Shopify custom pixel.
The limits come from the sandbox. A custom pixel doesn’t run on your page. It runs in a hidden iframe, and GTM runs inside that iframe with it:
- No access to the page. GTM can’t see clicks, forms, scroll or page content. Click triggers, element visibility and DOM variables don’t work. Only the Shopify events you subscribe to, and custom events your theme publishes with
Shopify.analytics.publish, reach GTM. - Preview mode doesn’t work. Tag Assistant can’t connect to a container inside the sandbox. You test with the Pixel Helper, the browser console, GA4 DebugView and the network tab, then publish.
- Wrong page URL by default. The iframe has its own address, so GA4 records the sandbox URL unless you send
page_locationandpage_referrerfromevent.context.document. - Cookies need care. GA4’s client ID and session ID must stay the same between your store pages and the checkout. If they don’t, purchases show up as Direct or Unassigned. See how to track Shopify checkout inside the pixel sandbox and Shopify purchases attributed to Direct or Unassigned.
This option is a good fit if your tracking is standard ecommerce events for GA4 and ad platforms. It’s a poor fit if you need clicks, forms or anything else that happens on the page.
Option 3: theme for store pages, pixel for the checkout
This hybrid is what I use when a store needs page interactions or custom events on top of standard ecommerce tracking. GTM in theme.liquid handles store pages, with Preview mode and page triggers. A second, smaller custom pixel handles only the checkout steps and the purchase.
The rule that makes it work: each event comes from exactly one place. The theme sends page_view, view_item and add_to_cart. The pixel subscribes only to checkout events, never to page_viewed or product_added_to_cart, which would duplicate them.
A checkout-only pixel looks like this:
const GTM_ID = "GTM-XXXXXXX";
window.dataLayer = window.dataLayer || [];
(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_ID);
const CHECKOUT_EVENTS = {
checkout_started: "begin_checkout",
checkout_shipping_info_submitted: "add_shipping_info",
payment_info_submitted: "add_payment_info",
checkout_completed: "purchase"
};
for (const [shopifyEvent, ga4Event] of Object.entries(CHECKOUT_EVENTS)) {
analytics.subscribe(shopifyEvent, (event) => {
const checkout = event.data.checkout;
const doc = event.context.document;
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: ga4Event,
page_location: doc.location.href,
page_referrer: doc.referrer,
ecommerce: {
transaction_id: checkout.order?.id,
value: Number(checkout.totalPrice?.amount),
currency: checkout.currencyCode,
items: checkout.lineItems.map((line) => ({
item_id: line.variant?.sku || line.variant?.product?.id,
item_name: line.title,
item_variant: line.variant?.title,
price: Number(line.variant?.price?.amount),
quantity: line.quantity
}))
}
});
});
}
You can use the same container ID in the theme and the pixel, or a separate container for the checkout. One container is easier to maintain. Two containers make it harder to fire a store-page tag in the checkout by mistake.
The hard part is not the code but the continuity. The checkout’s GA4 hits must carry the same client ID and session ID as the store pages, and the same consent state. Before you trust this setup, place a test order and compare the client ID on a product page with the one on the purchase. The Shopify tracking QA checklist lists the checks.
Option 4: a GTM app (Addingwell, Stape and others)
An app does options 1 to 3 for you: it injects GTM on your store pages without editing the theme, builds a GA4-style ecommerce dataLayer, and gives you a custom pixel for the checkout. You still configure the tags in GTM yourself. These apps install the plumbing, not the tracking.
The two I recommend most often both come from server-side GTM hosts.
Addingwell
Addingwell’s Shopify app (“GTM & DataLayer”) is free to install and needs only a GTM web container.
- GTM on every store page through a theme app embed, so it survives theme changes. You can set a different GTM container per Shopify Market.
- A custom pixel for the checkout, with code you paste into Customer events.
- A GA4-named dataLayer:
page_view,view_item_list,select_item,view_item,search,add_to_cart,remove_from_cart,view_cart,begin_checkout,add_contact_info,add_shipping_info,add_payment_info,purchase, pluslogin,sign_upand a consent update event. Events includeuser_data, also hashed, for enhanced conversions and Meta, and the purchase includes whether it’s a first order. - A ready-made GTM container template you can import, and an optional suffix on event names if other tools already push events with the same names.
- With an Addingwell server container: GTM loaded from your own domain, so ad blockers block it less, and Cookie Restore, which keeps GA4 cookies alive longer in Safari.
- Limit: you can’t add your own custom events through the app.
Stape
Stape’s Shopify app (Conversion Tracking, listed in the App Store as “Server GTM”) is also free to install.
- GTM on every page, including pages built outside your theme by page builder apps.
- Ecommerce dataLayer events enabled with a checkbox, including the checkout through Customer events.
- Purchase and refund webhooks sent from Shopify to your server container. Orders reach your server even when the browser doesn’t send the purchase.
- Custom loader and Cookie Keeper with a Stape server container: GTM loaded from your own subdomain, and cookies kept longer.
Which one?
| Addingwell app | Stape app | |
|---|---|---|
| Price of the app | Free to install | Free to install |
| Works without their server | Yes, web GTM only | Yes, but built around a server container |
| Checkout tracking | Custom pixel | Customer events |
| Order webhooks to server GTM | No | Yes, purchase and refund |
| Cookie extension | Cookie Restore | Cookie Keeper |
| GTM template | Yes | Yes, through Stape’s setup tools |
| Best fit | European stores, simpler setups, French or English support | Technical teams, stores that want webhooks and many add-ons |
In practice, pick the app that matches your server-side host, because the extra features only work with it. I compare the two hosts in detail in Addingwell vs Stape.
Other apps
Elevar and Analyzify are paid apps that go further: a maintained dataLayer, server-side destinations and support included. They make sense if you want a product with a subscription rather than a setup you own. See Elevar vs Analyzify vs Stape vs custom GTM.
Whatever app you install, remove any GTM code you pasted in theme.liquid before, and any custom pixel that loads GTM. Two containers loading the same tags is the most common cause of duplicate events.
Option 5: add server-side GTM
Every option above runs GTM in the browser. Server-side GTM adds a second container, hosted on Addingwell, Stape or Google Cloud, on your own subdomain such as data.yourstore.com. Browser tags send their events to it, and it forwards them to GA4, Google Ads, Meta and others.
- Fewer losses to ad blockers and browser limits, because requests go to your own domain.
- Longer-lived cookies, set by your server instead of by JavaScript, especially important in Safari.
- Meta Conversions API, TikTok Events API and enhanced conversions sent from one place, with deduplication.
- Control over the data you send to each platform.
It doesn’t replace the web setup: you still need options 2, 3 or 4 to collect the events. It’s an upgrade worth making once you spend real money on ads. Costs and trade-offs are in Shopify server-side tracking: what it fixes, what it doesn’t, and what it costs.
What about the Google & YouTube app?
Shopify’s Google & YouTube app connects GA4, Google Ads and Merchant Center without GTM. It’s officially supported, and Google recommends it for Google tags on Shopify. If you only use Google tools and need nothing custom, it can be enough. See Shopify GA4 setup: native app vs GTM vs tracking apps.
If you add GTM, decide which one sends GA4 and Google Ads conversions. Most stores keep the app for the Merchant Center product feed and turn off its GA4 and conversion tracking, so GTM is the only source. Running both counts every purchase twice: see duplicate purchase events on Shopify.
Set up the GTM container
Installing GTM only loads an empty container. For GA4 ecommerce, you need at least:
- A Google tag with your GA4 measurement ID, firing on initialization. In a checkout pixel, set
page_locationandpage_referrerfrom dataLayer variables. - A GA4 event tag with the event name from
{{Event}}and “Send ecommerce data” turned on, triggered by a custom event trigger matching your ecommerce events. - Consent settings on each tag, and Consent Mode defaults set before any tag fires, usually by your cookie banner’s GTM template.
- Ad platform tags (Google Ads conversion, Meta, TikTok) on the purchase event, with the transaction ID for deduplication.
If you use the Addingwell or Stape app, start from their container template rather than building this by hand.
Test your Shopify GTM setup
- Store pages: open GTM Preview on your store. Check that the container loads once, and that
view_itemandadd_to_cartfire once with the right items and value. - Checkout: Preview won’t follow you there. Open the Shopify Pixel Helper and the console, start a checkout and check that each checkout event fires once.
- Purchase: place a real test order, with a discount code if you want to check discounts. In GA4 DebugView, check the purchase, its transaction ID, value and currency.
- Continuity: compare the GA4 client ID on a product page and on the purchase. They must match.
- Consent: refuse cookies and repeat. Tags must respect the choice on store pages and in the checkout.
- A week later: compare GA4 purchases with Shopify orders. Read the gap as described in why GA4 shows fewer purchases than Shopify.
Common problems
- Purchases counted twice: GTM and the Google & YouTube app both send GA4, or the theme and a pixel both send the same event. Keep one source per event.
- No purchase at all: GTM is only in
theme.liquid, the custom pixel isn’t connected, or its customer privacy setting blocks it until consent that the banner never passes to the checkout. - Preview mode doesn’t connect on the checkout: expected. It can’t connect to a container inside the pixel sandbox.
- Page paths look like
/wpm@…/sandbox/in GA4: the pixel isn’t sendingpage_location. - Purchases credited to Direct, Unassigned or paypal.com: client ID or session lost between the store and the checkout, or payment referrals not excluded. See fixing paypal.com / referral.
- GTM missing on some pages: landing pages built by a page builder app don’t use
theme.liquid. An app embed, or the builder’s own code settings, fixes it.
Frequently asked questions
Can I add Google Tag Manager to Shopify without coding?
Yes. The Addingwell and Stape apps install GTM on your store pages and give you a ready-made pixel for the checkout. You still configure tags in GTM, but you don’t edit your theme.
Do I need Shopify Plus to use GTM?
No. Theme code, custom pixels and the apps above work on every Shopify plan. Plus used to be required to run GTM in the checkout with checkout.liquid, which no longer exists.
Can GTM track the Shopify thank-you page?
Only through a pixel in Customer events. Theme code and the old Additional scripts box no longer run there. Use the checkout_completed event for the purchase.
Why doesn’t GTM Preview mode work on my Shopify checkout?
The checkout runs GTM inside the custom pixel’s sandbox iframe, which Tag Assistant can’t connect to. Test with the Shopify Pixel Helper, the console and GA4 DebugView instead.
Should I install GTM in theme.liquid and in a custom pixel?
Yes, if they send different events: store page events from the theme, checkout events from the pixel. No, if both send the same events, which creates duplicates.
Where is theme.liquid in Shopify?
Online Store → Themes → … next to your live theme → Edit code → Layout → theme.liquid.
Is server-side GTM required on Shopify?
No, but it’s worth it once you run paid ads: it recovers conversions lost to browsers and ad blockers and sends Meta and Google server events from one place.
Which option should you choose?
- You want GTM working this week, without code: the Addingwell or Stape app, matched to your server-side host.
- You need custom events, page interactions or full control: the hybrid, theme for store pages and a checkout-only pixel.
- You only need standard ecommerce events: GTM in a custom pixel, or an app.
- You spend on Google, Meta or TikTok ads: any of the above, plus server-side GTM.
- You only use Google tools: the Google & YouTube app may be enough.
If you’d rather have it set up and checked against your orders, my Starter package installs GTM and GA4 with Consent Mode v2 for 1,300€, and the Professional package adds server-side tracking for every ad platform for 3,500€. See the Shopify tracking packages or book a free 30-minute call.