Server-side events · Setup reference
Conversions API Tag for Google Tag Manager (server-side), by Meta checker
Meta's open-source server GTM tag template reads events claimed by the GA4 client in your tagging server, renames GA4 events to Meta standard events, and POSTs them to the Conversions API. It hashes plain customer data for you and reads fbp/fbc from the _fbp/_fbc cookies or the fbclid on page_location. Dedup with the browser pixel only works if you pass an event_id parameter on the GA4 event that matches the pixel's eventID.
Read from the official documentation on 9 November 2026. Sources are listed at the end.
Check your own setup
Good fit. Copy the JSON body the tag sends (e.g. from server-container Preview) into capi-event-checker. It checks fbc/fbp format, that event_time is within 7 days, action_source, that em/ph etc. are hashed, that event_id is present for dedup, and value/currency on Purchase. It does not inspect your GTM containers, the GA4 client, or whether the web pixel uses the same eventID.
Open the Meta CAPI Event CheckerEndpoint and authentication
POST https://graph.facebook.com/{API_VERSION}/{PIXEL_ID}/events
Tag fields Pixel ID and API Access Token (a Conversions API access token generated in Events Manager); the template appends it as the access_token query parameter.
Standard event names
Spelled exactly as Server-side GTM + Meta expects them. A near miss is treated as a different event.
| Event | Use it for |
|---|---|
| PageView | from GA4 page_view (also gtm.dom) |
| ViewContent | from GA4 view_item |
| Search | from GA4 search; search_term -> custom_data.search_string |
| AddToCart | from GA4 add_to_cart |
| AddToWishlist | from GA4 add_to_wishlist |
| InitiateCheckout | from GA4 begin_checkout |
| AddPaymentInfo | from GA4 add_payment_info |
| Purchase | from GA4 purchase; value, currency and transaction_id (-> custom_data.order_id) are read from the event |
| Lead | from GA4 generate_lead |
| CompleteRegistration | from GA4 sign_up |
Required and recommended fields
| Field | What it needs |
|---|---|
| Pixel ID | tag field (required) |
| API Access Token | tag field (required) |
| Action Source | tag field or an action_source event parameter; Meta requires action_source on every server event |
| event_id | copied from the GA4 event's event_id parameter. Nothing generates it for you, so add it on the web GA4 tag and to the pixel's eventID. |
| page_location / user_agent / ip_override | mapped to event_source_url, client_user_agent and client_ip_address. Meta requires event_source_url and client_user_agent for website events. |
Match keys and hashing
| Key | Normalise and hash |
|---|---|
| user_data.email_address -> em | Template trims, lowercases and SHA-256 hashes unless the value is already a 64-character hex hash |
| user_data.phone_number -> ph | The template removes only the first "+", "-", space, "(" and ")" it finds (template.tpl line 263 uses a plain string replace), then SHA-256 hashes. "+1 (555) 444-1234" becomes "1555 4441234" and won't match. Send digits only, with country code (15554441234), or a pre-hashed x-fb-ud-ph |
| user_data.address.first_name/last_name/city/region/postal_code/country -> fn/ln/ct/st/zp/country | Template SHA-256 hashes (trim + lowercase). It does not apply Meta's full normalisation, e.g. state codes or 5-digit US zips. |
| x-fb-ud-* parameters (em, ph, fn, ln, ge, db, external_id...) | Used as-is: x-fb-ud-ge, db and external_id are passed through unhashed, so hash them yourself |
Click ids
| Click id | Where it comes from |
|---|---|
| fbc | From x-fb-ck-fbc or the _fbc cookie. If page_location carries ?fbclid=, the template builds fb.<subdomainIndex>.<timestampMillis>.<fbclid>. |
| fbp | From x-fb-ck-fbp or the _fbp cookie |
| Extend Meta Pixel cookies (fbp/fbc) | Optional checkbox: after a 2xx response the tag re-sets _fbc/_fbp as first-party cookies with a default max-age of 90 days. |
Deduplication
- Meta treats a pixel event and a Conversions API event as the same when the pixel eventID equals the server event_id AND the pixel event name equals the server event_name.
- Pixel syntax: eventID is the 4th fbq argument, e.g. fbq('track', 'Purchase', {value: 12, currency: 'USD'}, {eventID: 'EVENT_ID'}).
- Duplicates sent to the same pixel ID are discarded only if they arrive within 48 hours of the first one; Meta generally keeps the event received first.
- Template behaviour: event.event_id = the incoming event's event_id, with no fallback. If the GA4 event has no event_id parameter, server events go without one and duplicate the browser pixel.
Time limits and batch sizes
- event_time = the event's event_time if present, otherwise the server's current time in Unix seconds.
- Meta rejects a request if any event_time is more than 7 days old.
- One event per request (data: [event]); the template uses a fixed Graph API version in code (v25.0 at time of check).
How to test before you trust it
- Test Event Code tag field: Fill 'Test Event Code' (or send test_event_code on the event) with the code from Events Manager > Test Events, and clear it afterwards
- GTM server container Preview: Preview the server container, trigger events on the site, and confirm the tag fired and the request returned 2xx (the tag calls gtmOnFailure otherwise)
- Meta Test Events (Events Manager): Events Manager > Data Sources > your pixel > Test Events generates a test ID; send it as test_event_code and remove it before production (events with it are still processed).
Why events arrive but don't attribute
- Formatted phone numbers: the template strips only the first occurrence of each separator, so "+1 (555) 444-1234" is hashed with a space still in it and never matches. Put digits-only numbers with the country code in user_data.phone_number, or send x-fb-ud-ph already normalised and hashed.
- No event_id on the GA4 event, or a different value on the pixel's eventID, means pixel and server Purchases both count.
- Unmapped GA4 event names are passed through unchanged (e.g. a custom 'checkout_complete' arrives as a custom event, not Purchase).
- Action Source left empty and no action_source on the event: Meta requires action_source.
- The tagging server must receive page_location and user_agent, or website events miss event_source_url/client_user_agent, which Meta requires.
- Pre-hashed x-fb-ud-* values are sent verbatim, while plain user_data.* values are hashed. Mixing the two, or sending unhashed x-fb-ud-* values, breaks matching.
- Leaving Test Event Code filled after launch: test events are still processed, but the field is meant for testing only.
Sources
- GitHub facebookincubator/ConversionsAPI-Tag-for-GoogleTagManager (README + template.tpl)
- ConversionsAPI-Tag-for-GoogleTagManager template.tpl (phone normalisation, line 263)
- Meta for Developers: Handling duplicate pixel and Conversions API events
- Meta for Developers: Server event parameters
- Meta for Developers: Customer information parameters
- Meta for Developers: Using the Conversions API (Test Events, limits)
Platforms change these rules without notice. If a source says something different from this page, the source wins.