Installing GTM on Shopify in 2026 — Complete Guide

1. The Recommended Method: Shopify's Custom Pixels + Web Pixels API
Shopify has moved away from direct theme code injection for tracking. The Customer Events system (via Web Pixels API) is now the standard approach.
Why this matters:
Shopify's checkout is sandboxed — you can't inject arbitrary scripts into checkout pages on non-Plus stores
Custom Pixels run in a sandbox iframe, which affects how GTM behaves
Direct theme injection still works for non-checkout pages, but you'll have gaps in conversion tracking
2. Setup — Two-Part Installation
Part A: Theme Code (Head & Body snippets)
This covers all pages except checkout.
Step 1: Go to Shopify Admin → Online Store → Themes → Edit Code
Step 2: Open theme.liquid
Step 3: Paste this right after the opening <head> tag:
<!-- 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 -->
Step 4: Paste this right 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) -->
Part B: Custom Pixel (for Checkout & Post-Purchase Tracking)
This is critical — without this, you lose conversion/purchase data.
Step 1: Go to Shopify Admin → Settings → Customer events
Step 2: Click Add custom pixel
Step 3: Name it GTM Checkout Tracking
Step 4: Paste this code:
// GTM Custom Pixel for Shopify Checkout
const script = document.createElement('script');
script.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX';
script.async = true;
document.head.appendChild(script);
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
// Subscribe to Shopify standard events
analytics.subscribe('page_viewed', (event) => {
window.dataLayer.push({
event: 'page_view',
page_location: event.context.document.location.href,
page_title: event.context.document.title
});
});
analytics.subscribe('product_viewed', (event) => {
window.dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: event.data.productVariant?.id,
item_name: event.data.productVariant?.title,
price: event.data.productVariant?.price?.amount,
currency: event.data.productVariant?.price?.currencyCode
}]
}
});
});
analytics.subscribe('cart_viewed', (event) => {
window.dataLayer.push({
event: 'view_cart',
ecommerce: {
items: event.data.cart?.lines?.map(line => ({
item_id: line.merchandise?.id,
item_name: line.merchandise?.title,
price: line.merchandise?.price?.amount,
quantity: line.quantity
}))
}
});
});
analytics.subscribe('product_added_to_cart', (event) => {
window.dataLayer.push({
event: 'add_to_cart',
ecommerce: {
items: [{
item_id: event.data.cartLine?.merchandise?.id,
item_name: event.data.cartLine?.merchandise?.title,
price: event.data.cartLine?.merchandise?.price?.amount,
quantity: event.data.cartLine?.quantity
}]
}
});
});
analytics.subscribe('checkout_started', (event) => {
window.dataLayer.push({
event: 'begin_checkout',
ecommerce: {
value: event.data.checkout?.totalPrice?.amount,
currency: event.data.checkout?.currencyCode,
items: event.data.checkout?.lineItems?.map(item => ({
item_id: item.variant?.id,
item_name: item.title,
price: item.variant?.price?.amount,
quantity: item.quantity
}))
}
});
});
analytics.subscribe('payment_info_submitted', (event) => {
window.dataLayer.push({
event: 'add_payment_info',
ecommerce: {
value: event.data.checkout?.totalPrice?.amount,
currency: event.data.checkout?.currencyCode
}
});
});
analytics.subscribe('checkout_completed', (event) => {
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: event.data.checkout?.order?.id,
value: event.data.checkout?.totalPrice?.amount,
tax: event.data.checkout?.totalTax?.amount,
shipping: event.data.checkout?.shippingLine?.price?.amount,
currency: event.data.checkout?.currencyCode,
items: event.data.checkout?.lineItems?.map(item => ({
item_id: item.variant?.id,
item_name: item.title,
price: item.variant?.price?.amount,
quantity: item.quantity
}))
}
});
});
Step 5: Set Customer data sharing to "Not required" (or adjust based on your consent needs)
Step 6: Click Save → then Connect
3. Important Caveats
Sandbox Limitations
Custom Pixels run in a sandboxed iframe, which means:
Cookies set by GTM tags inside the pixel won't share with the main page
Facebook Pixel, Google Ads, GA4 — these work fine via GTM in the sandbox for event tracking
Session stitching between browse → checkout can be tricky — use Shopify's built-in integrations for Facebook/Google where possible as a backup
Consent Mode
For your clients in Taiwan/Asia, if GDPR-style compliance isn't required, this is simpler. But if needed:
Implement Google Consent Mode v2 in your GTM container
Use the pixel's permission settings to control when it fires
Server-Side GTM (Advanced)
For clients like ALUXE or JOYCOLORi where data accuracy is critical:
Consider setting up server-side GTM (sGTM) as a proxy
This bypasses ad blocker issues and improves data quality
Runs on Google Cloud or a custom domain endpoint
4. Testing Checklist
GTM Preview Mode — Use GTM's debug/preview to verify tags fire on browsing pages
Place a test order — Verify
purchaseevent fires with correcttransaction_id,value, anditemsGA4 DebugView — Check real-time events in GA4
Facebook Events Manager — If running Meta Pixel via GTM, verify events in Test Events
Check for duplicates — Make sure you're not double-firing if Shopify's native Google/Meta integrations are also active
5. Common Pitfalls
| Issue | Solution |
| Purchase event not firing | Make sure custom pixel is Connected (not just saved) |
| Duplicate transactions | Disable Shopify's native GA4 integration if using GTM for GA4 |
| GTM tags blocked by ad blockers | Consider server-side GTM |
| Cookie/session mismatch between site and checkout | Use Shopify's first-party integrations as backup for key conversions |
| dataLayer events not appearing in GTM Preview | Preview mode doesn't work inside the sandbox — test with real events |
Quick Summary
For your Shopify clients, the two-part approach (theme.liquid + Custom Pixel) gives you the best coverage. For high-value e-commerce clients, layer in server-side GTM for maximum data accuracy. Always test with a real order before going live.
Need me to help configure specific GTM tags (GA4, Meta, Google Ads conversions) inside the container as well?





