Meta Ads CAPI
Technical guide for media buyers: server-side Full CAPI. sGTM architecture, deduplication, EU consent, troubleshooting.
1Role / Purpose
Meta CAPI (Conversions API) is the server-side destination that replaces the browser Meta pixel. In our stack this is a Full CAPI architecture: no Meta pixel runs in the browser at all.
This setup delivers:
- 100% server-side tracking through the sGTM
- Strict GDPR compliance (EU-only consent)
- Robust attribution despite cookie restrictions (ITP, adblockers)
- Deterministic deduplication through event_id
- Less dependence on browser pixels
- Automatic Advanced Matching (server-side SHA-256 hashing)
The system rests on a single event source (the GTM Web dataLayer) to rule out duplication. No event is sent to Meta straight from the browser.
2Dual-Send Architecture
The architecture is a dual-send: the browser pushes events to the DataLayer, and the sGTM server routes them to Meta CAPI. There is no browser Meta pixel: this is Full CAPI, server-only.
Full data flow
Browser (DataLayer)
|
GTM Web (Consent Mode + DataLayer)
|
GA4 Config Tag (technical transport)
|
HTTP request → sGTM custom domain (first-party)
|
sGTM (server)
├── GA4 Client (receives the request)
│ ├── GA4 Server Tag → Google Analytics 4
│ ├── META – CAPI – All Events → Meta Conversions API
│ └── GADS – Conv – purchase → Google Ads
│
└── Server-side enrichment:
• Automatic SHA-256 hashing (email, phone, address)
• Attribution cookies (fbp, fbc)
• event_id for deduplication
• Consent Mode v2 signals forwardedCore principles
- No browser Meta pixel: Full CAPI, server-only
- No duplicate client + server send
- One source only: the GTM Web dataLayer
- Consent required before any marketing tracking
- GA4 used purely as technical transport
- Attribution cookies persisted first-party by Addingwell (cookie restore)
3CAPI Data Flow
Here is what Meta receives through CAPI versus what a browser pixel would normally send. In Full CAPI mode, everything goes through the server.
| Parameter | Value |
|---|---|
| Mode | Full CAPI (server-only) |
| sGTM tag | META – CAPI – All Events |
| Deduplication | event_id = transaction_id (purchase) |
| Attribution cookies | fbp + fbc (1P cookies, persisted by cookie restore) |
| Advanced Matching | Automatic SHA-256 (email, phone, address) |
| Consent transport | Consent Mode v2 signals forwarded to the server |
What CAPI forwards
The sGTM server sends Meta:
- Event name (PageView, ViewContent, AddToCart, InitiateCheckout, Purchase)
- Event ID (for deduplication)
- Hashed user data: email, phone, address (SHA-256)
- Attribution: fbp (browser ID), fbc (click ID from fbclid)
- Ecommerce: value, currency, content_ids, content_type, num_items
- Server URL: action_source = "website"
What CAPI does NOT receive (vs a browser pixel)
- No _fbp cookie read directly by the browser (GTM Web reads it and forwards it to the server)
- No instant PageView on load (the server must receive the GA4 request first)
- No dynamic retargeting through the JS pixel (use Meta catalogues instead)
4LPV Warning (Landing Page View)
Full CAPI limitation
The LPV rate (Landing Page Views / Link Clicks) is structurally lower in Full CAPI mode, because there is no browser pixel counting page views instantly.
LPV no longer represents
An actual browser pixel load (there is no Meta JS pixel)
But it does represent
A server-side estimated signal (page_view through the sGTM)
Why LPV comes out lower
Expected causes in Full CAPI:
- Fast navigation (tab closed before the server request lands)
- Consent declined (no event sent)
- Adblockers (blocking the GA4 transport request)
- Quick bounces before the page finishes loading
- Network latency between browser and sGTM
Monitor in Events Manager
Check Meta Events Manager > Diagnostics. If the LPV/Link Clicks ratio drops below 50%, verify the sGTM transport is answering 200.
What this means for media buyers
LPV Rate must not be used to judge traffic quality or optimise campaigns. Use conversion metrics (Purchase, ATC) instead.
5EMQ / Event Match Quality
Event Match Quality (EMQ) is Meta's score for how well server events match Meta users. A high score is essential for attribution and campaign optimisation.
| Score | Quality | Impact |
|---|---|---|
| > 8/10 | Excellent | Optimal attribution, reliable campaign optimisation |
| 6-8/10 | Good | Sound attribution, a few signals missing |
| < 6/10 | Weak | Degraded attribution, campaign optimisation compromised |
What drives EMQ
- _fbp present (browser ID): first-party cookie persisted by cookie restore
- _fbc present (click ID): generated from the fbclid parameter
- Hashed user data (email, phone, address): automatic server-side SHA-256
- External ID (a stable user identifier)
- IP address and User Agent (forwarded automatically by the sGTM)
How to check EMQ
Go to Meta Events Manager > Test Events. Every server event shows its EMQ score. Target: > 6/10 on every conversion event.
Improving EMQ
- 1Check that Addingwell cookie restore is active (fbp and fbc persisted first-party)
- 2Check that Advanced Matching is configured on the Meta CAPI sGTM tag
- 3Make sure user_data (email, phone) is in the DataLayer at purchase time
- 4Check that the sGTM custom domain answers correctly (cookies written under the right domain)
6Events & Parameters
Single event source
Every event comes exclusively from:
GTM Web → dataLayer → GA4 event → sGTM → Meta CAPI
No event may be sent directly from:
- The Shopify theme
- A browser Meta pixel
- An external app (Facebook & Instagram app)
- The server, bypassing the GA4 transport
E-commerce funnel
| User action | GA4 | Meta CAPI |
|---|---|---|
| Page loaded | page_view | PageView (optional) |
| Product viewed | view_item | ViewContent |
| Added to cart | add_to_cart | AddToCart |
| Checkout started | begin_checkout | InitiateCheckout |
| Purchase | purchase | Purchase |
Key parameters per event
| Parameter | GA4 | Meta CAPI | Description |
|---|---|---|---|
| Transaction ID | transaction_id | event_id | Unique identifier for deduplication |
| Value | value | value | Order total |
| Currency | currency | currency | ISO 4217 code (EUR, USD) |
| Products | items[] | contents[] | Product array |
| User email | user_data.email | em (hashed) | Server-side SHA-256 hash |
7Deduplication Logic
Global unique identifier
transaction_id = Meta event_id
The same identifier is used for:
- GA4 purchase
- Meta Purchase
- Every server event
Deduplication rules
- Exactly one purchase must exist in the dataLayer
- No second client-side Meta send (there is no browser pixel)
- No purchase sent directly by Addingwell
- No double mapping in the sGTM
Full CAPI = no browser/server deduplication
In Full CAPI mode there is no browser Meta pixel. Deduplication only concerns potential DataLayer duplicates (a purchase firing twice, for instance).
8Attribution Identifiers
Facebook click identifiers
_fbp
- First-party cookie
- Identifies the browser
- Used for probabilistic matching
- Persisted by Addingwell cookie restore (works around Safari ITP)
_fbc
- Generated from the fbclid parameter
- Enables click-to-conversion attribution
- Persisted by Addingwell cookie restore
Forwarding to CAPI
The identifiers are:
- 1Read in GTM Web (1P cookies)
- 2Injected into the GA4 events (transport)
- 3Forwarded through the sGTM to Meta CAPI
- 4Enriched with server-side SHA-256 hashing (user_data)
9EU Consent
Consent handling
Consent is handled exclusively by:
Cookiebot + GTM Web Consent Mode v2 Signals Meta CAPI requires: • ad_storage = granted • ad_user_data = granted Cookiebot category: Marketing
No consent is handled in:
- The Shopify theme
- The Custom Pixel
- The sGTM server
Rules
Without marketing consent:
- No Meta event is sent
- No identifier is forwarded
- No matching is possible
- Consent Mode v2 signals still reach the server (but the Meta tag does not fire)
10Configuration
sGTM tag: META -- CAPI -- All Events
| Parameter | Value | Source |
|---|---|---|
| Pixel ID | Connectors variable | meta_pixel_id in GTM |
| Access Token | Connectors variable | meta_access_token in GTM |
| Event Name | Automatic mapping | GA4 event → Meta event |
| Event ID | transaction_id / event_id | DataLayer |
| User Data | Automatic SHA-256 hash | Addingwell template |
| Action Source | website | Fixed |
Credentials needed
- 1Pixel ID: Meta Events Manager > Data Sources > Pixel > Settings
- 2Access Token: Meta Events Manager > Settings > Generate Access Token (System User)
Access Token
The Access Token must be generated through a System User with the ads_management and ads_read permissions. Never use a personal token.
11Verification
Quick check
- 1Open Meta Events Manager > Test Events
- 2Browse the site with consent accepted
- 3Check that events show up as "Server" (not "Browser")
- 4Check the EMQ score is > 6/10 on each event
- 5Place a test order and check the Purchase
Phase 3: Meta destinations checklist
Meta CAPI-specific verification, lifted from the full QA process (Step 5: Verify).
12Troubleshooting
Check:
- 1Marketing consent active (ad_storage + ad_user_data = granted)
- 2purchase present in GA4 Realtime
- 3Received in the sGTM (server logs)
- 4CAPI send visible in Meta Test Events
Check:
- _fbp present (is cookie restore active?)
- _fbc present (was fbclid captured?)
- Hashed user_data present (email, phone)
- sGTM custom domain answering 200
Check:
- Access Token invalid — regenerate under Events Manager > Settings > System Users
- Pixel ID wrong — check the variable in GTM
- Consent not granted: check ad_storage and ad_user_data are granted
- sGTM transport failing — check the Addingwell server logs
Causes (expected behaviour in Full CAPI):
- Without a browser pixel, not every page_view is captured
- Fast navigation, tabs closed before the server request
- Monitor under Events Manager > Diagnostics
- If the LPV/Link Clicks ratio is < 50%, check the sGTM transport answers 200
Possible causes:
- Consent declined (no identifier forwarded)
- No fbclid in the URL (fbc never generated)
- Cookie restore disabled in Addingwell
- Unqualified traffic (bots, scrapers)
Causes:
- Duplicate purchase in the dataLayer (thank-you page reloaded)
- Double mapping in the sGTM (two Meta tags active)
- event_id not stable between sends
- "Facebook & Instagram" app still active (native pixel)
Check:
- Cookie restore disabled under Addingwell > Settings
- sGTM custom domain not configured (cookies are written by the first-party sGTM domain)
- Check under DevTools > Application > Cookies with the store domain
13Metrics You Can Optimise On
The KPIs that hold up in this Full CAPI setup:
- Purchase volume
- Cost per Purchase
- ROAS
- AddToCart Rate
- Checkout Rate
Metrics to avoid
- LPV Rate (Landing Page Views / Link Clicks): structurally low in Full CAPI
- Reach vs Impressions without consent context
- Any ratio based on the browser pixel (which does not exist here)
14Responsibilities Matrix
- dataLayer integrity
- Event firing
- Consent management
- Identifier persistence (cookie restore)
- Deduplication
- sGTM and tag configuration
- Campaign optimisation
- Choosing the optimisation events
- Attribution analysis
- Reading performance
- Monitoring EMQ in Events Manager
- Diagnosing cross-platform gaps
- Validating volumes
- Cross-tool debugging
- Monitoring LPV rate and EMQ
15Weekly Media-Buyer Checklist
Every week, check:
Check the layer you just set up
Scan the store: 41 checks read what it now sends to GA4, Meta and Google Ads.