Meta CAPI (Server-Side)
The Meta Conversions API (CAPI) sends conversion events directly from your server to Meta’s servers, bypassing browser restrictions, ad blockers, and ITP entirely. When implemented alongside the browser pixel with proper deduplication, CAPI typically increases reported conversions by 15-30% by recovering events the pixel missed.
This article covers the complete CAPI setup via server-side GTM.
Why CAPI exists
Section titled “Why CAPI exists”Browser-based pixels face three structural problems:
- Ad blockers prevent the pixel script from loading entirely
- ITP caps cookie lifetimes, shortening attribution windows for Safari users
- iOS 14+ App Tracking Transparency reduced signal quality from mobile users
Meta introduced CAPI to give advertisers a browser-independent path to conversion data. Server-to-server requests are not affected by any of these restrictions.
The right model: Run pixel and CAPI simultaneously, deduplicate with event_id. The pixel provides browser-side signals (like fbp, fbclid, live session context). CAPI provides completeness. Together, you get both accuracy and coverage.
Prerequisites
Section titled “Prerequisites”Before configuring the sGTM tag:
- A running sGTM container (see the Server-Side GTM section for setup)
- Meta Pixel ID (numeric ID from Events Manager)
- A CAPI Access Token (generated in Events Manager)
- The Facebook Pixel template installed in your sGTM container
Generating a CAPI Access Token:
- Go to Meta Events Manager → your Pixel → Settings
- Scroll to Conversions API
- Under “Direct integration,” click “Generate Access Token”
- Copy and store the token securely — you cannot view it again after navigating away
sGTM container setup
Section titled “sGTM container setup”The Meta CAPI tag in sGTM is configured in the server-side container, not the web container.
-
In your sGTM container, go to Tags → New
-
Click the Tag Type field → Community Template Gallery
-
Search for “Facebook Conversions API” — select Meta’s official template
-
Configure the tag with:
- Pixel ID: your numeric Pixel ID
- Access Token: your Variable referencing the stored access token
- Test Event Code: (use during testing — remove for production)
-
Configure the event mapping (covered in the next section)
-
Set the Firing Trigger to fire on GA4 events you want to send to Meta (e.g.,
purchase,add_to_cart,lead)
Event mapping: GA4 events to Meta standard events
Section titled “Event mapping: GA4 events to Meta standard events”Your GA4 events arrive at sGTM. The CAPI tag must map those events to Meta’s standard event names.
Common event mappings:
| GA4 event name | Meta standard event | Notes |
|---|---|---|
page_view | PageView | Optional — mostly useful for remarketing |
view_item | ViewContent | Pass content_ids and content_type |
add_to_cart | AddToCart | Pass content_ids, value, currency |
begin_checkout | InitiateCheckout | Pass cart value |
purchase | Purchase | Critical — pass value, currency, order_id |
generate_lead | Lead | Pass content_name |
sign_up | CompleteRegistration | |
search | Search | Pass search_string |
add_payment_info | AddPaymentInfo |
In the CAPI tag template, you configure the event name mapping and the parameter mapping. The template reads values from the sGTM Event Model (which is built from the incoming GA4 event).
Parameter mapping for Purchase:
Event Name: Purchase Value: {{Event Data - ecommerce.value}} Currency: {{Event Data - ecommerce.currency}} Content IDs: {{Event Data - ecommerce.items.0.item_id}} (or mapped array) Content Type: product Order ID: {{Event Data - ecommerce.transaction_id}} Event ID: {{Event Data - event_id}} ← CRITICAL for deduplicationUser data: the key to high Event Match Quality
Section titled “User data: the key to high Event Match Quality”Meta’s Event Match Quality (EMQ) score (0-10) measures how well CAPI events match to Meta user profiles. Higher EMQ means better attribution and optimization. The single biggest factor in EMQ is the quality and quantity of user data you send with each event.
User data parameters (all SHA-256 hashed):
| Parameter | Source | Impact |
|---|---|---|
em (email) | User’s email address | Very high |
ph (phone) | User’s phone number | High |
fbc | _fbc cookie (Facebook click ID) | High |
fbp | _fbp cookie (Meta browser pixel ID) | Medium |
fn + ln | First and last name | Medium |
ct, st, zp, country | Location | Medium |
client_ip_address | IP from request headers | Medium |
client_user_agent | User agent from request | Medium |
Reading _fbc and _fbp from cookies:
These cookies are set by the Meta Pixel JavaScript. Your sGTM server can read them from the incoming request cookies using Cookie Variables:
- Create a Cookie Variable: name
_fbp, returns the Facebook browser pixel cookie - Create a Cookie Variable: name
_fbc, returns the Facebook click ID cookie (set when users arrive from Facebook ads withfbclidparameter)
Reading IP and User Agent from request headers:
In sGTM, use Request Header Variables:
- Variable type: Request Header, header name
X-Forwarded-Fororclient-ipfor IP address - Variable type: Request Header, header name
user-agentfor user agent
Hashing user data in sGTM:
The Meta CAPI Community Template handles SHA-256 hashing automatically for standard user parameters. Map your raw email variable to the template’s email field — the template hashes it before sending.
For custom hashing in sGTM:
// In a Custom Variable template in sGTMconst crypto = require('crypto');const email = data.email;if (!email) return undefined;const normalized = email.trim().toLowerCase();return crypto.createHash('sha256').update(normalized).digest('hex');Event deduplication with event_id
Section titled “Event deduplication with event_id”Without deduplication, Meta counts every event it receives — both from the browser pixel and from CAPI. A single purchase becomes two conversions, doubling your reported ROAS and corrupting your campaign optimization signals.
The deduplication mechanism:
- Generate a unique
event_idfor each event occurrence in your client-side code - Push it to the dataLayer alongside the event
- Include it in the client-side Meta Pixel event
- Pass it through to sGTM’s Event Model
- Include it in the CAPI event with the same value
Meta matches events with the same event_name and event_id within a 48-hour window and counts them as a single event.
Generating event_id in the dataLayer:
// Utility function for generating UUIDsfunction generateEventId() { return 'ev-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);}
// On purchase eventdataLayer.push({ ecommerce: null });dataLayer.push({ event: 'purchase', event_id: generateEventId(), // ← Same value used in pixel and CAPI ecommerce: { transaction_id: 'ORDER-12345', currency: 'USD', value: 79.99, items: [...] }});In client-side GTM: Map {{DL - Event ID}} to the Meta Pixel tag’s event_id parameter.
In sGTM: The event_id arrives in the GA4 event as an event parameter. Read it with an Event Data variable and map it to the CAPI tag’s event_id field.
Verifying deduplication is working:
In Meta Events Manager, look at the Event Quality section. There is a “Duplicate percentage” metric for each event. If deduplication is working, this should be 0% or very close to 0%. A high duplicate percentage means your event_id values are not matching between pixel and CAPI.
Testing with Test Event Code
Section titled “Testing with Test Event Code”Before deploying to production, use Meta’s Test Event Code to verify CAPI events without polluting your real data:
- In Meta Events Manager → your Pixel → Test Events
- Click “Create Test Event Code” — you get a code like
TEST12345 - In your sGTM CAPI tag configuration, add the Test Event Code field with this value
- Fire test events on your site
- Events appear in the Test Events panel in Events Manager within seconds
- Verify: event names, parameter values, user data fields, Event Match Quality preview
- Remove the Test Event Code before deploying to production — events sent with a test code do not appear in production reporting
Gateway API vs. full CAPI
Section titled “Gateway API vs. full CAPI”Meta offers two server-side options:
Conversions API Gateway (managed by Meta): Meta hosts the server-side infrastructure. You configure it in Events Manager and point your pixel to Meta’s endpoint. Simpler to set up, no sGTM required, but less flexible — you cannot enrich events with server-side data or route to multiple platforms.
Full CAPI via sGTM (this article): You control the server. More complex, but you can enrich events with data from your database (user segments, LTV, order profitability), route the same event to multiple platforms, and integrate with your existing server-side data pipeline.
For most e-commerce implementations, full CAPI via sGTM is the right choice.
Improving Event Match Quality
Section titled “Improving Event Match Quality”EMQ is the most important metric to monitor after deploying CAPI. Common steps to improve it:
-
Add email for logged-in users. If users are authenticated, their email is the single most impactful data point. Pass a hashed email variable populated only when a user is logged in.
-
Read
_fbcand_fbpcookies. These are Meta-specific cookies that significantly improve match quality. Ensure your cookie variables are reading them correctly. -
Include client IP and user agent. These are easy to read from request headers and consistently improve EMQ.
-
Pass phone number for checkout events. If users provide phone numbers during checkout, include the hashed value for Purchase and AddPaymentInfo events.
-
Add geographic data when available. City, state, zip code, and country all contribute to matching.
An EMQ score below 6/10 indicates you are missing key user data. An EMQ of 8-10 is excellent.
Common mistakes
Section titled “Common mistakes”Forgetting the Test Event Code after testing
Section titled “Forgetting the Test Event Code after testing”The test code makes events appear in the Test Events panel instead of standard reporting. Events sent with a test code are NOT counted in campaigns. Remove it before production deployment.
Sending the same event_id for multiple events
Section titled “Sending the same event_id for multiple events”Each event occurrence must have a unique ID. If you send the same event_id for every purchase on your site, Meta’s deduplication will discard all but the first.
Not reading _fbc from the URL parameter
Section titled “Not reading _fbc from the URL parameter”When a user arrives from a Facebook ad, the URL contains fbclid. The Meta Pixel JavaScript reads this and stores it in the _fbc cookie. But if the pixel is blocked, _fbc never gets set. Consider reading fbclid from the URL on the server side and setting _fbc yourself:
// sGTM custom logic: read fbclid from the request URL// and construct the _fbc value manuallyconst fbclid = request.queryParameter('fbclid');if (fbclid) { const fbc = `fb.1.${Date.now()}.${fbclid}`; // Use this as the fbc value in the CAPI event}Sending CAPI events without consent
Section titled “Sending CAPI events without consent”CAPI events must still respect user consent. If a user has not consented to advertising tracking, the sGTM CAPI tag should not fire. Implement consent checking in your sGTM container with the same care as your client-side tags.