Shopify heeft fundamenteel veranderd hoe tracking in en rond de checkout werkt. Het tijdperk van scripts plakken in checkout.liquid of het veld “additional scripts” is voorbij: Shopify Plus-shops verloren die scripts op de bedank- en orderstatuspagina in augustus 2025, en alle andere Shopify-shops volgden op 26 augustus 2026. Alles wat daar nog geplakt stond, stopte gewoon met vuren. Zonder melding.
De ondersteunde route is tegenwoordig een custom pixel, gebouwd op Shopify’s Customer Events-systeem. In deze gids lees je hoe je Google Tag Manager op Shopify draait via een custom pixel, inclusief een compleet, direct bruikbaar script dat GA4-ecommerce-events naar je datalayer pusht. Geschreven voor shopeigenaren en marketeers die hun eigen Shopify GTM-setup beheren.
Wat er veranderde in Shopify-tracking
Shopify verving zijn oude, scriptvriendelijke checkout door checkout extensibility: een afgeschermde checkout waarin je geen eigen JavaScript kunt injecteren. Tracking verhuisde naar een apart systeem met pixels, te beheren via Instellingen en dan Klantgebeurtenissen in je Shopify-admin.
De tijdlijn is relevant als je data recent kapotging. Shopify Plus-shops verloren additional scripts en checkout.liquid op de bedank- en orderstatuspagina op 28 augustus 2025. Alle andere shops verloren additional scripts en script tags op die pagina’s op 26 augustus 2026. Er kwam geen foutmelding: legacy scripts hielden er simpelweg mee op.
Dus zakten je Shopify-conversiecijfers eind augustus 2026 ineens in en heb je nooit gemigreerd? Dan is dit vrijwel zeker de oorzaak. De oplossing is de setup hieronder.
Zo werkt de custom pixel-route
Een custom pixel is een stukje JavaScript dat Shopify draait in een sandbox, gescheiden van je storefront-pagina’s. Binnen die sandbox abonneer je je op Shopify’s standaardevents via de Web Pixels API: paginaweergaves, productweergaves, toevoegingen aan de winkelwagen, gestarte checkouts, afgeronde checkouts en meer.
Het patroon voor GTM-gebruikers is simpel. De pixel laadt GTM binnen de sandbox, luistert naar Shopify’s events met analytics.subscribe(), vertaalt elk event naar een GA4-datalayer-push, en je GTM-tags nemen het vanaf daar over.
De sandbox heeft gevolgen die je moet kennen. De pixel kan de pagina zelf niet zien of aanraken, dus tags die directe DOM-toegang nodig hebben, werken vanaf hier niet. En omdat de sandbox geïsoleerd is, werkt testen anders dan je gewend bent; daarover meer in stap 5.
![]()
GTM instellen als custom pixel in zes stappen
Stap 1: inventariseer wat je nu hebt
Zet op een rij welke events je nu meet en waar de code staat: GTM in theme.liquid, scripts in het thema, oude additional scripts, of apps die hun eigen pixels injecteren. Deze inventarisatie bepaalt wat je migreert en wat je uitzet, en voorkomt de klassieker: twee setups die dezelfde aankoop meten.
Stap 2: maak je GTM-container klaar
Controleer dat je publicatierechten hebt, exporteer een back-up van de huidige container en houd je container-ID (formaat GTM-XXXXXXX) bij de hand.
Stap 3: voeg de custom pixel toe in Shopify
- Ga in de Shopify-admin naar Instellingen en dan Klantgebeurtenissen.
- Klik op Aangepaste pixel toevoegen en geef hem een naam, bijvoorbeeld Google Tag Manager.
- Loop de Klantprivacy-instellingen van de pixel na. Die bepalen of de pixel op toestemming wacht voordat hij draait.
- Plak het script uit de volgende sectie, vervang het container-ID, en klik op Opslaan en Verbinden.
Eén eerlijke opmerking over die privacy-instellingen. Zet je de pixel op “geen toestemming vereist”, dan vuurt hij voor elke bezoeker, consent of niet. Verkoop je aan bezoekers in de EER of het VK en draai je een cookiebanner, dan ondermijnt die sluiproute je consent-setup. Stem de toestemmingsinstellingen van de pixel af op je werkelijke consentstrategie, in plaats van standaard de meest permissieve optie te kiezen.
Het GTM custom pixel-script
Vervang GTM-YOUR_ID door je eigen container-ID. Het script laadt GTM, abonneert zich op Shopify’s standaardevents en pusht ze naar de datalayer in GA4-ecommerce-formaat, inclusief een uniek event_id per event dat je kunt hergebruiken voor deduplicatie.
(function () {
// --- 0) Utilities ---
function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// --- 1) Load GTM ---
(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-YOUR_ID');
// Ensure dataLayer exists
window.dataLayer = window.dataLayer || [];
// --- 2) Normalizers (GA4 item format) ---
function fromVariant(variant, qty) {
if (!variant) return null;
const p = variant.product || {};
const priceAmount = (variant.price && (variant.price.amount ?? variant.price)) || 0;
const currency = (variant.price && variant.price.currencyCode) || undefined;
return {
item_id: variant.sku || variant.id || p.id || 'unknown',
item_name: p.title || 'unknown',
item_brand: p.vendor || undefined,
item_category: p.type || undefined,
item_variant: variant.title || undefined,
price: Number(priceAmount),
quantity: Number(qty || 1),
currency: currency
};
}
function fromCartLine(line) {
const v = line?.merchandise;
return fromVariant(v, line?.quantity || 1);
}
function fromCheckoutLine(line) {
const v = line?.variant;
const base = fromVariant(v, line?.quantity || 1);
if (!base) return null;
const amount = line?.finalLinePrice?.amount ?? v?.price?.amount ?? 0;
const code = line?.finalLinePrice?.currencyCode ?? v?.price?.currencyCode;
base.price = Number(amount);
base.currency = code;
return base;
}
// --- 3) Subscriptions (GA4-style events) ---
// page_view
analytics.subscribe('page_viewed', function (e) {
const shop = e?.data?.shop || {};
window.dataLayer.push({
event: 'page_view',
event_id: uuid(),
currency: shop.currency
});
});
// view_item
analytics.subscribe('product_viewed', function (e) {
const v = e?.data?.productVariant;
const item = fromVariant(v, 1);
if (item) {
window.dataLayer.push({
event: 'view_item',
event_id: uuid(),
ecommerce: {
currency: item.currency,
items: [item]
}
});
}
});
// add_to_cart
analytics.subscribe('product_added_to_cart', function (e) {
const line = e?.data?.cartLine;
const item = fromCartLine(line);
if (item) {
window.dataLayer.push({
event: 'add_to_cart',
event_id: uuid(),
ecommerce: {
currency: item.currency,
items: [item]
}
});
}
});
// remove_from_cart
analytics.subscribe('product_removed_from_cart', function (e) {
const line = e?.data?.cartLine;
const item = fromCartLine(line);
if (item) {
window.dataLayer.push({
event: 'remove_from_cart',
event_id: uuid(),
ecommerce: {
currency: item.currency,
items: [item]
}
});
}
});
// view_cart
analytics.subscribe('cart_viewed', function (e) {
const lines = e?.data?.cart?.lines || [];
const items = lines.map(fromCartLine).filter(Boolean);
if (items.length) {
const currency = items.find(i => i.currency)?.currency;
window.dataLayer.push({
event: 'view_cart',
event_id: uuid(),
ecommerce: {
currency: currency,
items: items
}
});
}
});
// begin_checkout
analytics.subscribe('checkout_started', function (e) {
const co = e?.data?.checkout;
const lines = co?.lineItems || [];
const items = lines.map(fromCheckoutLine).filter(Boolean);
window.dataLayer.push({
event: 'begin_checkout',
event_id: uuid(),
ecommerce: {
value: Number(co?.totalPrice?.amount || 0),
currency: co?.currencyCode,
items
}
});
});
// purchase (raw GID transaction_id)
analytics.subscribe('checkout_completed', function (e) {
const co = e?.data?.checkout || {};
const lines = co?.lineItems || [];
const items = lines.map(fromCheckoutLine).filter(Boolean);
const rawId = co?.order?.id || 'unknown'; // keep full Shopify GID
window.dataLayer.push({
event: 'purchase',
event_id: uuid(),
ecommerce: {
transaction_id: rawId, // raw GID preserved
value: Number(co?.totalPrice?.amount || 0),
currency: co?.currencyCode,
items
}
});
});
// view_item_list (collections)
analytics.subscribe('collection_viewed', function (e) {
const col = e?.data?.collection;
const variants = col?.productVariants || [];
const items = variants.map(v => fromVariant(v, 1)).filter(Boolean);
if (items.length) {
window.dataLayer.push({
event: 'view_item_list',
event_id: uuid(),
ecommerce: {
item_list_id: col?.id,
item_list_name: col?.title,
items
}
});
}
});
// search + view_search_results
analytics.subscribe('search_submitted', function (e) {
const sr = e?.data?.searchResult;
const q = sr?.query;
window.dataLayer.push({
event: 'search',
event_id: uuid(),
search_term: q
});
const variants = sr?.productVariants || [];
const items = variants.map(v => fromVariant(v, 1)).filter(Boolean);
if (items.length) {
const currency = items.find(i => i.currency)?.currency;
window.dataLayer.push({
event: 'view_search_results',
event_id: uuid(),
ecommerce: {
currency: currency,
items
}
});
}
});
})();
Stap 4: koppel de events aan je tags in GTM
Maak in GTM custom event-triggers voor page_view, view_item, add_to_cart, begin_checkout, purchase en de andere events die het script pusht. Hang die triggers aan je GA4-eventtags, Google Ads-conversietags en Meta-pixeltags, en lees waardes en items uit de datalayer.
Stap 5: test het goed
Omdat de pixel in een sandbox draait, maakt de Preview-modus van GTM er vaak geen verbinding mee zoals op een normale pagina. Test met Shopify’s eigen pixeltesttools, de GA4 DebugView en realtime rapporten, en een testorder als dat kan. Controleer dat het purchase-event één keer binnenkomt, met de juiste waarde, valuta en items.
Stap 6: publiceer en monitor
Publiceer de GTM-container en houd je platformen daarna een paar dagen in de gaten. Vergelijk Shopify’s eigen ordertelling met de aankopen in GA4 en je advertentieplatformen. De cijfers zullen nooit tot op de komma matchen, maar ze horen dichtbij elkaar te liggen en stabiel te zijn.
Veelgemaakte fouten die wij zien
1. Twee tracking-setups tegelijk draaien. GTM in je thema en GTM in een custom pixel kunnen allebei events afvuren voor dezelfde sessie. Bepaal welke route welk event bezit. Een gangbare verdeling: het thema doet storefront-gedrag, de pixel bezit checkout en purchase.
2. De checkout-events als optioneel behandelen. De events die het meest tellen voor je advertenties, begin_checkout en purchase, zijn precies de events die de oude scripts niet meer kunnen versturen. Heb je de storefront gemigreerd maar de checkout-events niet, dan stopt je funneldata waar het geld begint.
3. De meest permissieve privacy-instelling. Een pixel die consent negeert, oogt geweldig in de cijfers, tot je bedenkt wat hij met je compliance doet. Stel toestemmingen bewust in.
4. Transactie-ID’s die niet matchen. Het script bewaart Shopify’s volledige order-GID als transaction_id. Welk ID-formaat je ook kiest: gebruik het consequent in GA4, Google Ads en elke server-side setup, anders breekt de deduplicatie en tellen orders dubbel.
Klaar voor de volgende stap? Ga server-side
De custom pixel repareert de client-side, maar browsertracking verliest nog steeds signaal aan adblockers, Safari’s tracking prevention en consentkeuzes. De logische vervolgstap is dezelfde datalayer-events door een servercontainer routeren. Onze gidsen over server-side tagging, de tool-opties en de GTM- en TAGGRS-setup behandelen die route in detail, en de Meta Conversions API sluit naadloos aan op het event_id dat dit script al genereert.
Hoe Coby dit aanpakt
Bij Coby zijn Shopify-trackingmigraties standaardwerk binnen onze data- en analyticsdienst, meestal binnen een dag afgerond. We werken tracking first: de meetlaag wordt gerepareerd voordat iemand aan campagne-instellingen komt, want campagnes die optimaliseren op kapotte aankoopdata optimaliseren het verkeerde.
Die volgorde betaalt zich uit. Voor een B2B-klant hielp het repareren van het meetfundament, vóór het opschalen van campagnes, om van twee tot drie leads per maand naar vier tot vijf per week te gaan. In een Shopify-shop geldt hetzelfde principe voor elk purchase-event waar je advertenties van leren.
Conclusie
De checkout van Shopify draait je oude scripts niet meer, en sinds 26 augustus 2026 geldt dat voor elke shop, niet alleen Plus. De custom pixel-route hierboven herstelt full-funnel tracking: GTM in een sandbox, Shopify’s standaardevents vertaald naar een GA4-datalayer, en je tags daar bovenop. Stel de privacytoestemmingen bewust in, test het purchase-event grondig en zet uit wat de pixel vervangt.
Laat je het liever regelen, inclusief de server-side laag? Neem contact op, dan zorgen wij voor je migratie.
Veelgestelde vragen
Heb ik nog een custom pixel nodig als GTM al in mijn thema staat?
Ja, voor de checkout. GTM in theme.liquid blijft werken op storefront-pagina’s, maar de checkout en de bedankpagina geven events alleen vrij via Customer Events. Purchase-tracking heeft dus de pixelroute nodig.
Wat gebeurde er met additional scripts op de bedankpagina?
Shopify zette ze uit als onderdeel van checkout extensibility: op 28 augustus 2025 voor Plus-shops en op 26 augustus 2026 voor alle andere shops. Legacy scripts stopten met vuren zonder waarschuwing of foutmelding.
Welke events kan de custom pixel opvangen?
Shopify’s standaardevents omvatten paginaweergaves, product- en collectieweergaves, zoeken, winkelwagenacties, gestarte checkouts en afgeronde checkouts. Het script in deze gids koppelt de belangrijkste aan GA4-datalayer-events.
Waarom verbindt de GTM Preview-modus niet met mijn pixel?
Custom pixels draaien in een sandbox, waar de Preview-modus vaak niet aan kan koppelen. Test in plaats daarvan met Shopify’s pixeltesttools, de GA4 DebugView en realtime rapporten.
Kan ik via deze setup ook Meta-events versturen?
Ja. Trigger je Meta-pixeltags in GTM vanaf dezelfde datalayer-events, en hergebruik het event_id van het script voor deduplicatie als je later de Conversions API toevoegt.
Heb ik Shopify Plus nodig voor custom pixels?
Nee. Custom pixels zijn beschikbaar op alle Shopify-abonnementen via Instellingen en dan Klantgebeurtenissen. Plus voegt vooral diepere checkout-UI-aanpassing toe, niet het pixelsysteem zelf.
Geschreven door Marloes Slotboom, founder van Coby Agency. Laatst bijgewerkt: oktober 2026.