GA4 op Shopify heeft twee gangbare instappen: de Google & YouTube-app, of een custom pixel in Customer Events die de events zelf verstuurt. Beide zetten ecommerce-data in je GA4-property. Ze verschillen in wie de mapping schrijft, wie hem onderhoudt, en wat je kunt aanpassen.
Deze gids vergelijkt ze op het niveau van het mechanisme: wat de purchase afvuurt, wat de transaction ID draagt, hoe consent wordt gerespecteerd, en wat er stukgaat. Er komt geen winnaar uit, want het juiste antwoord hangt af van de controle die je nodig hebt en het onderhoud dat je kunt dragen. Server-side doorsturen valt buiten dit stuk; dat is een andere laag.
Wat doet de Google & YouTube-app eigenlijk?
De Google & YouTube-app is een verkoopkanaal-app van Shopify, gebouwd met Google. Hij laadt de tags van Google op de winkel en mapt de standaardevents van Shopify naar de aanbevolen ecommerce-namen van GA4, zodat een purchase GA4 bereikt zonder dat iemand pixelcode schrijft. Jij configureert hem; Shopify en Google onderhouden de mapping.
Hij abonneert zich op de standaardevents van Shopify en mapt ze naar de aanbevolen namen van GA4: product_viewed naar view_item, product_added_to_cart naar add_to_cart, checkout_started naar begin_checkout, en checkout_completed naar purchase, met de omliggende cart-, list-, shipping- en search-events inbegrepen.
De purchase is een compleet GA4-ecommerce-event: transaction_id, value, currency, tax, shipping, coupon, market_id, en een items-array met id, name, brand, variant, price, quantity en SKU. Value is subtotaal min kortingen, exclusief verzending en belasting, en valt standaard terug op USD wanneer het event geen valuta draagt. Elk event draagt ook shopify_event_name en een event_id. Klantgegevens zoals e-mail en telefoon worden alleen toegevoegd waar consent en de Analytics-instellingen dat toestaan.
Wat je bestuurt is configuratie, geen code: je verbindt je GA4-property of voegt handmatig een Google-tag toe, en je kunt events binnen GA4 filteren op shopify_event_name. De mapping, de value-formule en de parameterset liggen vast. Google stelt dat niet elke op code gebaseerde tagfunctie wordt ondersteund, vanwege de sandboxbeperkingen van Shopify.
De purchase is zowel de kracht als het plafond van de app. Hij vuurt af vanuit checkout_completed, dus hij is niet afhankelijk van een bedankpagina-script dat in leven blijft, maar hij verstuurt alleen wat het schema van Google definieert: een refund-event, een custom parameter of je eigen value-definitie valt buiten zijn gedocumenteerde oppervlak.
Wat doet een custom pixel eigenlijk?
Een custom pixel is JavaScript dat je toevoegt onder Customer Events in het Shopify-admin. Het abonneert zich op de standaardevents van Shopify en stuurt GA4 wat jij het opdraagt, via gtag of een GTM-container die binnen de pixel is geladen. Jij kiest de eventnamen, de parameters, de items-array, de transaction_id en de consent-poort.
De pixel draait in de sandbox van Shopify. Custom pixels laden in een soepele sandbox — een iframe dat beperkt is tot scripts en formulieren — en kunnen niet bij het topframe, de DOM niet uitlezen en de dataLayer van de storefront niet delen. In ruil krijg je een gestructureerde event-payload en de Standard API van Shopify. Code die de pagina of window.dataLayer verwacht, vindt geen van beide, en daarom doen snippets die uit een themabestand zijn verplaatst niets.
Binnen de sandbox beslis jij alles wat de app voor je beslist: op welke events je je abonneert, hoe je ze noemt, hoe je items opbouwt, en wat je als transaction_id en value gebruikt. Een purchase-abonnement kan er als volgt uitzien:
analytics.subscribe('checkout_completed', (event) => {
const checkout = event.data.checkout;
gtag('event', 'purchase', {
transaction_id: checkout.order.id,
value: checkout.subtotalPrice.amount,
currency: checkout.currencyCode,
items: checkout.lineItems.map((item) => ({
item_id: item.variant?.sku ?? String(item.variant?.id),
item_name: item.title,
price: item.variant?.price?.amount,
quantity: item.quantity,
})),
});
});
Consent moet jij regelen. De pixel kan init.customerPrivacy lezen en zich abonneren op visitorConsentCollected, en bepaalt vervolgens wat hij wel en niet verstuurt. Shopify draait pixels in consent-regio’s al pas nadat de vereiste doeleinden zijn toegekend, en speelt eerdere events daarna opnieuw af; jouw poort komt daar bovenop.
De ruil is eigenaarschap. Niets werkt je pixel bij wanneer Shopify een schema verandert, dus jij bent eigenaar van de mapping, het testen en de fix. En Google stelt dat Google-tags binnen een custom pixel geen ondersteunde configuratie zijn, dat het hun gedrag niet kan garanderen en dat de ondersteuning van Google die problemen daar niet kan oplossen. Dat is geen reden om een pixel te vermijden die je nodig hebt. De betrouwbaarheid rust dan op jou.
Wat gebeurt er als je beide tegelijk draait?
De app en een custom pixel tegelijk draaien betekent twee purchase-events voor dezelfde bestelling. GA4 dedupliceert purchases die een identieke transaction_id delen, maar wanneer de twee routes verschillende of lege ID’s versturen, telt GA4 de bestelling dubbel. Een lege transaction_id voegt niet-gerelateerde purchases samen.
De regel van GA4 is specifiek: het voegt purchase-events met dezelfde transaction_id op webstreams samen, en een lege transaction_id zorgt ervoor dat GA4 niet-gerelateerde purchases samen dedupliceert. Het helpt alleen wanneer beide routes dezelfde niet-lege identifier versturen. Ze kiezen die onafhankelijk van elkaar — de app leidt zijn eigen ID af uit de bestelling, jouw pixel gebruikt wat jij hebt gekozen — dus een mismatch komt vaak voor en GA4 ziet twee bestellingen. De oplossing is structureel: draai één purchase-route, zet de ene uit voordat de andere aan gaat, en bevestig in DebugView dat één testbestelling één purchase oplevert.
Naast elkaar
De tabel vergelijkt de twee op de criteria die de meeste implementaties bepalen. Het is een beschrijving van afwegingen, geen ranglijst.
Vergelijkingstabel — scrol horizontaal om alle kolommen te bekijken
| Criterium | Google & YouTube-app | Custom pixel (gtag of GTM) |
|---|---|---|
| Eventbron | Standaardevents van Shopify, gemapt door de app | Jouw abonnementen op de standaardevents van Shopify |
| Dekking van purchase en refund | Gedocumenteerde mapping tot en met purchase; refund-aanpassing valt niet binnen het configureerbare oppervlak | Jij verstuurt purchase en eventuele refund-events; jij bepaalt de dekking |
| Deduplicatie | De app genereert zijn eigen transaction_id en event_id | Jij kiest transaction_id en event_id |
| Omgaan met consent | Draait als pixel onder de Customer Privacy API van Shopify en respecteert de doeleinden die hij aangeeft | Jij leest het privacy-object en bepaalt zelf welke events erdoor mogen |
| Data-eigenaarschap | Mapping in eigendom van Shopify en Google; data belandt in jouw GA4-property | Logica in jouw eigendom; data belandt in jouw GA4-property |
| Afhankelijkheid en lock-in | Afhankelijk van de app en het Shopify-kanaal waar hij doorheen loopt | Afhankelijk van de sandbox en het eventschema van Shopify |
| Onderhoudslast | De leverancier onderhoudt de mapping terwijl het platform verandert | Jij onderhoudt elke schemawijziging en parameterwijziging |
| Voor wie het past | Winkels die GA4-ecommerce willen laten draaien met minimale code | Winkels die parameters, events of een poort nodig hebben die de app niet blootlegt |
Beslistabel
Koppel je situatie aan een startpunt. Dit zijn standaardkeuzes voor gangbare gevallen, geen regels; een winkel met een developer en ongebruikelijke rapportagebehoeften kan op de custom pixel uitkomen, zelfs waar de app zou werken.
Vergelijkingstabel — scrol horizontaal om alle kolommen te bekijken
| Als je situatie … is | Kies … |
|---|---|
| Je wilt standaard GA4-ecommerce-events laten draaien en niemand schrijft pixelcode | Google & YouTube-app |
Je hebt een event, een parameter of een items-veld nodig dat de app niet verstuurt | Custom pixel |
| Je moet precies bepalen wat er onder je consentbanner afvuurt en wanneer | Custom pixel, met je eigen poort |
Je migreert van Additional Scripts of checkout.liquid en wilt het ondersteunde pad | Google & YouTube-app |
| Je draait al een werkende custom pixel en wilt alleen het verouderde script weg | Houd de pixel, en zorg dat er geen tweede purchase-route actief is |
| Je wilt dat de event-mapping voor je wordt onderhouden terwijl Shopify de checkout verandert | Google & YouTube-app |
| Je verlies bestaat uit geblokkeerde of afgekapte requests, niet uit de mapping | Geen van beide op zichzelf — zie server-side tracking |
Wanneer je elk van beide niet gebruikt
Tegen een optie kiezen is makkelijker als je de harde randen kent. De app is het verkeerde gereedschap wanneer je configuratie nodig hebt die hij niet blootlegt; de custom pixel is verkeerd wanneer niemand hem kan onderhouden of wanneer je het door Google ondersteunde pad wilt. Geen van beide lost transportverlies op.
Grijp niet naar de Google & YouTube-app wanneer:
- Je een refund-event, een custom parameter of een andere value-definitie nodig hebt dan subtotaal min kortingen.
- Je dezelfde purchase moet routeren naar bestemmingen die zijn mapping niet bedient.
- Je consent-logica moet afwijken van de doeleinden die de app aangeeft.
Grijp niet naar een custom pixel wanneer:
- Niemand hem gaat beheren; elke schemawijziging van Shopify wordt een storing die opgemerkt moet worden.
- Je de configuratie wilt die Google ondersteunt. Google stelt dat Google-tags in een custom pixel niet ondersteund worden en dat de ondersteuning van Google ze niet oplost.
- Je vertrouwt op Tag Assistant of GTM Preview, die tags op de pagina debuggen en niet in de pixel-sandbox.
- Standaard ecommerce-mapping is alles wat je nodig hebt — je neemt onderhoud op je zonder winst.
Verwacht van geen van beide dat ze dit oplossen:
- Signaal dat verloren gaat aan adblockers, gesloten tabbladen of geweigerde consent. Dat is transport, en het antwoord is server-side levering, niet een andere browsertag.
- Een permanent verschil tussen GA4 en Shopify. De twee systemen tellen anders; reconciliatie is de methode, niet een betere pixel.
Hoe ik dit verifieer in echte implementaties
Ik verifieer door te tellen. Eén purchase-route hoort per bestelling één purchase op te leveren, zichtbaar in DebugView met een overeenkomende transaction_id, en te reconciliëren tegen een Shopify-orderexport. Al het andere — consent, items, currency — wordt tegen diezelfde bestelling gecontroleerd.
- Bevestig welke route de purchase bezit. Settings → Customer events toont de geregistreerde pixels. Wijs elke pixel aan die een purchase kan versturen; precies één zou dat moeten kunnen.
- Volg een live bestelling in DebugView. Debug een apparaat, doorloop een volledige checkout, en bevestig dat de
purchaseaankomt met zijntransaction_id,value,currencyenitems. Test meer dan één checkoutroute voordat je concludeert dat een tag dood is. - Controleer de sleutel tegen de bestelling. De
transaction_iddie GA4 ontving, moet niet leeg zijn, uniek voor die bestelling, en identiek op elke route die hem verstuurt. - Bevestig dat de advertentieplatforms het eens zijn. Waar Meta meespeelt, hoort Test Events in Events Manager één conversie voor de bestelling te tonen, niet één per browserroute.
- Reconciliëer de volgende dag. Vergelijk GA4-purchases op
transaction_idmet een Shopify-orderexport van een afgesloten periode — dezelfde methode van orderreconciliatie die in een trackingaudit wordt gebruikt. - Bewijs consent in beide richtingen. Bevestig met geweigerde consent dat de tags onderdrukt blijven; ken hem daarna toe en bevestig dat events doorstromen — zie Consent Mode v2.
Veelvoorkomende faalpatronen
De meeste storingen zijn niet exotisch. Het zijn een tweede purchase-route die blijft draaien, een lege transaction_id, een value die aan elke kant anders is gedefinieerd, of gesandboxte code die aannam dat hij de pagina kon lezen.
- Twee purchase-routes, twee ID’s. De app en een pixel vuren allebei af en versturen verschillende
transaction_id-waarden, waardoor GA4 de bestelling dubbel telt. - Een lege
transaction_id. GA4 dedupliceert elke purchase die hem draagt samen, waardoor niet-gerelateerde bestellingen samenvallen. - Een value op de verkeerde basis. De app verstuurt subtotaal min kortingen, exclusief verzending en belasting; een handgeschreven pixel die een brutototaal verstuurt, komt niet overeen met de GA4-rapportage of het netto van Shopify.
- Gesandboxte code die aannam dat hij de pagina kon lezen. Snippets die uit een themabestand zijn verplaatst, doen stilletjes niets, omdat de sandbox geen DOM en geen gedeelde dataLayer heeft.
- Debuggen met het verkeerde gereedschap. Een GTM-container in een pixel kan kapot lijken onder GTM Preview of Tag Assistant, die tags op de pagina debuggen en niet in de pixel-sandbox.
- Geen consent-poort in een custom pixel. Events blijven afvuren voor bezoekers die weigerden — een complianceprobleem, geen voorkeur.
- Een tag die nog in Additional Scripts staat. Na de upgrade naar checkout extensibility stopt het verouderde veld met uitvoeren, en valt de purchase stil zonder foutmelding.
Beperkingen
Geen van beide opties is een transportfix. Beide zijn afhankelijk van de pixel van Shopify die in de browser draait, dus bestellingen die sneuvelen door blockers, gesloten tabbladen of geweigerde consent blijven verloren, tenzij de levering server-side gaat. Beide laten GA4 anders tellen dan Shopify, omdat GA4 sessies attribueert terwijl Shopify bestellingen registreert, en geen enkele pixelkeuze verandert dat.
De custom pixel voegt eigenaarschap toe — schemawijzigingen, testen, en het door de leverancier aangegeven gebrek aan ondersteuning voor Google-tags daarbinnen. De app voegt een plafond toe: de mapping ligt vast, dus behoeften buiten zijn gedocumenteerde oppervlak hebben een andere route nodig. Geen van beide is een consent-omzeiling, en geen van beide maakt een cijfer dat niet is gereconcilieerd betrouwbaar.
Alternatieven
Als je probleem niet “welke pixel” is, kan het antwoord in een andere laag zitten. Server-side levering verstuurt de purchase vanuit de order-webhook van Shopify in plaats van vanuit de browser, wat het duurzame antwoord is voor signaal dat verloren gaat aan blockers — zie de server-side trackinggids. Offline conversie-imports dekken bestellingen die de browser nooit heeft gezien.
Als je een kapotte purchase repareert in plaats van een architectuur te kiezen, staat de stap-voor-stapopbouw in Het GA4 purchase-event op Shopify oplossen. Is het symptoom ontbrekende purchases, een groter wordend verschil of een kapotte checkout, begin dan bij GA4 registreert geen purchases, de omzetmismatch tussen GA4 en Shopify en kapotte Shopify-checkouttracking. Voor de onderliggende concepten, zie event ID, Consent Mode v2 en first-party tracking.