Instellen van AdPage Webhook Matching

Bewerkt

Webhook Matching zorgt dat je purchase-events server-side gevalideerd en ontdubbeld worden voordat ze naar GA4, Meta, Google Ads, TikTok of Pinterest gaan. Hieronder de zes stappen om dit live te zetten.

Wat doet Webhook Matching?

Browser-side purchase events kunnen worden geblokkeerd door ad-blockers, cookies, of ITP. Backend-webhooks vanuit je commerce-platform (Shopify, WooCommerce, PrestaShop, etc.) zijn server-side maar missen browser-context (gclid, user-agent, items array). De Webhook Matching van AdPage koppelt beide via een match-identifier, merged de payloads, en stuurt één gevalideerd event door. Resultaat: geen dubbele conversies, geen gemiste conversies.


Stap 1 — Activeer Webhook Matching in AdPage

  1. Open de AdPage container van je klant

  2. Ga naar Webhook request logs

  1. Zorg dat de callback url juist staat ingesteld. De endpoint staat standaard op data


Stap 2 — Upload de Tag Template in sGTM

  1. Open de server container in Google Tag Manager

  2. Ga naar Templates → Tag Templates → New

  3. Klik op de drie puntjes rechtsboven → Import → kies adpage-event-notifier.tpl. Je kunt deze hier downloaden: https://adpage.b-cdn.net/GTM-Templates/adpage-event-notifier.tpl

  4. Klik Save, de template "AdPage Event Notifier" verschijnt in de templates-lijst

  5. Maak twee tags aan met deze template:

    Tag 1 — Prepare (browser-side):

    • Mode: Prepare

    • Container ID: (uit AdPage, stap 1)

    • Platform preset: kies wat past (zie stap 3)

    • Affiliation: webshop-naam

    • Trigger: een browser-event vlak voor checkout (bv. view_cart, add_to_cart, of begin_checkout)

    Tag 2 — Trigger (server-side webhook):

    • Mode: Trigger

    • Container ID: idem

    • Platform preset: idem

    • Trigger: de webhook-event van je commerce-platform (bv. trytagging_purchase voor WC/PrestaShop, orders/create voor Shopify)


Stap 3 — Kies de juiste BasketKey (Matcher)

De BasketKey is wat Prepare en Trigger aan elkaar koppelt. Beide kanten moeten dezelfde waarde meesturen, anders matcht EN ze niet.

Kies in het veld Platform preset de juiste optie:

Setup

Preset

BasketKey

Klant heeft AdPage Tagging plugin/script geïnstalleerd

AdPage Tagging (universal)

user_id (uit trytagging_user_id cookie)

Native Shopify (zonder Tagging plugin)

Shopify

cart_token

Native Magento

Magento

quote_id

Native Lightspeed C-Series

Lightspeed

quote_id

Native Shopware 6

Shopware

cart_token

Iets anders / custom integratie

Custom

zelf invullen

Aanrader: voor 95% van onze klanten is AdPage Tagging (universal) de juiste keuze. Dit werkt platform-onafhankelijk omdat onze tagging-stack overal hetzelfde user_id UUID gebruikt — in de browser (cookie trytagging_user_id) én in de webhook (marketing.user_id).

Het veld Identifier-waarde override kun je leeg laten — de template haalt de waarde automatisch op uit event data of cookies. Vul alleen iets in als de auto-pull faalt; je ziet dat in de sGTM console-log als een error met de melding "Match identifier value could not be resolved".


Advies: bouw dit in twee fasen

Zet Webhook Matching niet in één keer volledig live. Werk in twee stappen:

Fase 1 — Matching valideren zonder door te sturen Richt Stap 1 t/m 3 in (AdPage-activatie, Prepare- en Trigger-tags, BasketKey), maar sla Stap 4 (Measurement Protocol client) nog over. Prepare en Trigger draaien dan al tegen elkaar, maar er wordt nog niets naar GA4 of de ad-platforms doorgestuurd. Laat dit een paar dagen tot een week draaien en volg de Match-gezondheid in het dashboard. Gebruik "Analyseer missed" en de Event details (Payload check, Stale cookies-uitsplitsing) om issues op te lossen.

Fase 2 — Pas omzetten als de match-rate goed is Is de match-rate stabiel en acceptabel (richtlijn: ruim boven 90%, en "Niet bereikt" grotendeels verklaarbaar/incidenteel)? Voer dan pas Stap 4 en verder uit om de Measurement Protocol client aan te maken en de purchase-events daadwerkelijk door te sturen naar GA4 en de gekoppelde platforms.

Waarom: als je de client meteen aanzet terwijl de matching nog niet goed staat, stuur je vanaf dag één onvolledige of dubbele conversiedata door naar GA4/Ads/Meta — en dat is achteraf lastiger te corrigeren dan vooraf te voorkomen.

Stap 4 - Measurement Protocol client aanmaken

De Webhook Matching callback arriveert op je sGTM /data endpoint. Daar moet een Client klaar staan om de binnenkomende Measurement Protocol-request te claimen en om te zetten naar een event dat downstream tags (GA4, Google Ads, FB CAPI, etc.) kunnen oppakken.

  1. Open de server container in Tag Manager

  2. Ga naar Clients → New

  3. Klik Choose client type → onder More kies Measurement Protocol (GA4)

  4. Geef de client een herkenbare naam, bv. Webhook Matching - GA4

  5. Vul de client-instellingen in:

    • Path / Activation: vul hier de standaard callback url in "/data"


Stap 5 — Purchase event doorsturen naar GA4

Om te voorkomen dat je 2 of 3 keer een purchase event gaat versturen (één keer vanuit de client-side GA4 request, één keer vanuit de Webhook Client, en één keer vanuit de Webhook Matching), zal je in de triggers op je GTM server container in moeten stellen dat er maar één purchase event doorgestuurd wordt.

1) Schakel de browser-purchase uit

In je GTM server container:

  • Open de bestaande Google Analytics tag en open de trigger

  • Voeg een voorwaarde toe die de Event Name 'purchase' tegenhoudt. Dus de exception: trigger wanneer event = purchase én event komt vanuit de GA4 Client.

2) Voeg een nieuwe trigger toe

In dezelfde Google Analytics tag voeg je nu een trigger toe:

  • Kies de grijze optie aangepast als trigger

  • Voeg de voorwaarde 'Client Name komt overeen met [client-naam die je zelf gekozen hebt]' toe

Als je die twee stappen uitvoert zal je dus een GA4 tag hebben met 2 triggers. Eén trigger die alle GA4 client events doorstuurt, behalve 'purchase'. En één trigger die de 'purchase' event doorstuurt vanaf je webhook matching client.

Stap 5 - Testen en debuggen

Voordat je live gaat, controleer je of Prepare en Trigger daadwerkelijk matchen.

Testen in preview modus

  1. Start Preview modus op zowel de web- als de server-container in GTM.

  2. Doorloop een testbestelling tot en met de bevestigingspagina.

  3. Controleer in de preview van de Prepare-tag (browser-side):

    • Basket ID (de BasketKey uit Stap 3) staat gevuld en is exact gelijk aan de waarde die je straks bij de Trigger-tag terugziet — dit is de gedeelde identifier die beide zijden aan elkaar koppelt.

  4. Controleer in de preview van de Trigger-tag (server-side, na binnenkomst webhook) dat dezelfde Basket ID aanwezig is.

  5. Zie je bij de Trigger geen match op basis van de Basket ID, ga terug naar Stap 3 (BasketKey/Matcher) en de Troubleshooting-melding "Match identifier value could not be resolved".

Webhook Logs gebruiken om de trigger te testen

Wil je de Trigger-kant testen zonder een nieuwe bestelling te plaatsen? Gebruik de Webhook Logs:

  1. Ga in AdPage naar de container → Webhook Logs (tabblad naast Webhook Matching).

  2. Zoek de gewenste webhook op transaction_id of reference_id.

  3. Klik op het replay-icoon (oranje) achter de rij.

  4. Start Preview modus op de server-container in GTM en kopieer de Debug Signal-header.

  5. Plak deze in het veld Preview Header in de "Webhook Replay"-popup en klik Versturen.

  6. De webhook wordt opnieuw verstuurd in debug-modus, zodat je in de GTM-preview precies ziet hoe de Trigger-tag deze specifieke payload verwerkt — zonder dat er een dubbele conversie naar GA4/Meta/etc. gaat.


Het Webhook Matching dashboard

Onder Webhook Matching → Match-gezondheid zie je in één oogopslag hoe goed Prepare en Trigger de afgelopen periode (standaard 7 dagen) matchen, en waar het misgaat.

Match-gezondheid lezen

  • Het percentage bovenaan is het aandeel orders dat succesvol is verwerkt (matched, in-app browser-afhandeling of cookieless), tegenover het totaal aantal binnengekomen orders.

  • Gematcht: Prepare en Trigger zijn gekoppeld op de Basket ID — dit is de "gezonde" flow.

  • In-app browsers: orders vanuit in-app browsers (Instagram/Facebook-app e.d.) waar cookies beperkt werken.

  • Cookieless: orders zonder trackable cookie, zie ook "Unconsented conversies doorsturen" in de Geavanceerd-sectie.

  • Niet bereikt: orders die niet zijn gematcht. Hover over dit segment voor de uitsplitsing naar oorzaak:

    • Stale cookies — de Prepare-cookie was al verlopen toen de Trigger binnenkwam (te lange tijd tussen checkout-start en orderbevestiging).

    • Overig/onbepaald — restcategorie, meestal incidenteel.

  • Onder de balk staat het aantal orders zonder consent — dit zijn orders die (deels) niet getrackt worden in GA4 omdat de bezoeker tracking heeft geweigerd.

  • Analyseer missed: draait een analyse op de "niet bereikt"-orders om te zien of Waarschijnlijkheids-matching of Trigger-only doorsturen (zie Geavanceerd) die alsnog had kunnen redden.

Event details bekijken

Klik op Details bij een rij in Recente events om een individueel event te inspecteren:

  • Status, Bron (Transaction ID en Callback-tijd (hoe snel de trigger de callback verwerkte) staan bovenaan.

  • Payload check laat zien of er een data-afwijking is gevonden, bv. "value ≠ som van items" wanneer het ordertotaal niet overeenkomt met de som van de items (binnen tax/shipping-tolerantie). Dit is een waarschuwing, geen blokkade — het event gaat gewoon door, maar het is de moeite waard om te checken of de klant-integratie de juiste velden meestuurt.

  • Tracking-consent toont of consent is toegestaan of geweigerd, met de onderliggende Consent Mode-vlaggen (analytics_storage, ad_storage, gcs).

  • Browser toont de user-agent, handig om patronen te herkennen (bv. veel "Niet bereikt" vanuit één browser/OS-combinatie).

  • Prepare buffered en Trigger verwerkt tonen de exacte timestamps van beide events — het verschil hiertussen is relevant bij "Stale cookies"-issues.

  • Onderaan vind je vier tabbladen: Outgoing payload (wat naar GA4/Meta/etc. is gestuurd), Prepare data, Order data en Trigger body (raw) — handig om te zien wat er binnenkwam vóór verwerking.

  • Kopieer payload en Replay… (zelfde replay-functie als in Webhook Logs) staan onderaan.

Stap 8 — Wat zit er in de outgoing payload

Event Notifier's callback naar sGTM bevat een complete payload die meteen bruikbaar is voor alle grote ad-platforms. Onze template forwarded automatisch:

GA4 (Measurement Protocol)

event_name:           "purchase"
client_id:            (van browser of webhook marketing.ga4_client_id)
transaction_id:       (van order)
value, tax, shipping: (van order)
currency:             EUR / USD / etc.
items[]:              (volledige array met item_id, item_name, price, quantity, item_brand, item_category, etc.)
engagement_time_msec: 100 (default)
page_location:        echte thank-you URL (Shopify Web Pixel sandbox-URLs worden automatisch opgeschoond)
gcs, gcd:             Consent state
ip_override:          server-side geocoding werkt

Meta CAPI (Facebook + Instagram)

fbp:                  _fbp cookie (Facebook browser ID)
fbc:                  _fbc cookie (Facebook click ID)
em:                   email (SHA256 wordt door FB CAPI tag gedaan)
fn, ln, ph:           first_name, last_name, phone (SHA256 idem)
zp, ct, st, country:  zip, city, state, country
external_id:          customer.id (cross-order stable)
client_ip_address:    IP voor IP-matching
client_user_agent:    UA voor browser-fingerprinting
event_id:             voor browser-pixel deduplicatie

Google Ads (Conversion + Remarketing)

_gcl_aw, _gcl_dc, _gcl_gb:  gclid cookies (set door Conversion Linker)
FPGCLAW, FPGCLDC:            first-party gclid variants
gclid, gbraid, wbraid:        URL-parameters (iOS app campaigns)
client_id, ga_session_id:     voor stiching met page_view events
value, currency:              conversion value

TikTok Events API

_ttp, ttp:            TikTok pixel cookie
ttclid:               TikTok click ID (uit URL ?ttclid=)
email, phone_number:  (TikTok gebruikt volledige veldnamen ipv FB's afkortingen)
first_name, last_name, city, state, zip_code, country_code: idem
external_id:          customer.id
ip, user_agent:       voor matching

Pinterest Conversions API

_epik, epik:          Pinterest click ID cookie + URL param
em, fn, ln, ph, zp:   (zelfde conventie als FB CAPI)
ct, st, country:      adres-velden
external_id:          customer.id
client_ip_address:    IP
client_user_agent:    UA

Consent forwarding (alle platforms)

EN stuurt de Consent Mode state in twee vormen mee zodat álle CAPI tags het kunnen respecteren:

ad_storage, ad_user_data, ad_personalization, analytics_storage: "granted"/"denied"
consent.ad_storage, consent.ad_user_data, …: idem (genest object)
gcs, gcd: Google Consent strings (voor GA4 / Google Ads)

Troubleshooting

"Match identifier value could not be resolved" — De BasketKey wordt niet gevonden in event data. Open in sGTM console de error-log → kijk in EventDataSnapshot waar de UUID staat → vul die pad in via "Identifier-waarde override" in de tag-config.

Trigger geeft 308 redirect — URL eindigt met /trigger/ zonder waarde. Betekent dezelfde root-cause als hierboven. Re-check de BasketKey resolutie.

Trigger geeft 400 — Body validatie faalt. Meestal omdat transaction_id of value leeg is. Bij AdPage Tagging plugin (WC/PS) zit dit in ecommerce.transaction_id — controleer dat de webhook die meestuurt.

missed status in EN logs — Trigger arriveerde zonder bijhorende Prepare. Browser-side Prepare faalde waarschijnlijk (ad-blocker, ITP, of geen browser-event vlak voor checkout). Check sGTM preview op de storefront.

callback_failed — sGTM ontvangt EN's callback niet. Check de callback URL in AdPage's tenant-config; meestal mist er een /data suffix of staat er een verkeerde subdomain.

Geavanceerd

  • Multi-market (Shopify Markets / multi-locale shops): vul in het veld GA4 Measurement IDs alle GA4 properties komma-gescheiden (bv. G-NL123, G-BE456, G-DE789). EN forwarded dan per-property de _ga_<MID> cookie zodat sGTM downstream kan routeren.

  • WooCommerce zonder Tagging plugin: vul de exacte wp_woocommerce_session_<hash> cookie-naam in het veld "WooCommerce session cookie naam".

  • Custom event identifier: kies preset = Custom en vul zelf identifier-naam + variabele-referentie in.

  • Duplicaat-preventie bij dubbele identifiers: komt een order zowel met een canonieke identifier (bv. vtnl-...) als met een kale variant (bv. alleen het ordernummer) binnen, dan wordt de kale variant genegeerd en gaat alleen de canonieke door.

  • Waarschijnlijkheids-matching: probeert een order die anders missed zou zijn alsnog te koppelen aan een recente Prepare op basis van items, bedrag, klant-identiteit en timing. Bij voldoende zekerheid wordt het event met status Waarschijnlijk (i.p.v. matched) naar GA4 gestuurd. Standaard uit — zet dit alleen aan als je dit per klant vertrouwt.

  • Trigger-only doorsturen: stuurt een order die anders missed zou zijn (geen Prepare, ook niet via waarschijnlijkheids-matching) tóch naar GA4, op basis van de GA4 client_id uit de ga-cookie van de Trigger zelf. Alleen mogelijk als die clientid aanwezig is — anders blijft de order missed. Status wordt Trigger-only. Standaard uit.

  • Unconsented conversies doorsturen: stuurt een order waarbij tracking-consent is geweigerd (dus geen GA4 client_id) tóch naar GA4, als privacy-veilige cookieless ping: een wegwerp-client_id met "denied"-consentvlaggen en zonder PII, zodat GA4 de conversie kan modelleren. Status wordt Unconsented. Standaard uit — zet dit alleen aan na overleg met de klant over privacy/consent, want dit stuurt data door ook al is er geen toestemming voor tracking gegeven.


Hulp nodig?

Heb je je klant in een platform-setup waar dit artikel niet op antwoord geeft — vraag het Tracking & Tools-team via Slack #adpage-tracking of mail support@adpage.io met de container-ID en een screenshot van de sGTM console-log.


Was dit artikel nuttig?

Onze excuses! Zou je ons meer willen vertellen?

Bedankt voor de feedback!

Er is een probleem opgetreden bij het verzenden van uw feedback
Controleer uw verbinding en probeer het opnieuw.