Meta Conversions API (CAPI)
The Conversions API is Meta's server-side tracking solution that sends events directly from your server to Meta, bypassing browser limitations.
Why Use Conversions API?
Browser Limitations
- Ad blockers prevent pixel from loading
- iOS 14+ App Tracking Transparency reduces data
- Browser privacy features block third-party cookies
- Network issues can cause missed events
Benefits of CAPI
- More accurate data: Events sent server-side are more reliable
- Better attribution: Improved event matching with customer data
- Redundancy: Works alongside browser pixel for complete coverage
- Privacy-friendly: Can hash customer data before sending
How It Works
flowchart LR
BROWSER[Browser] -->|Pixel| META[Meta]
SERVER[Your Server] -->|CAPI| META
BROWSER -->|Event| SERVER
Events can be sent via:
- Browser Pixel only - Traditional client-side
- CAPI only - Pure server-side
- Both (recommended) - Deduplicated using event_id
Implementation Options
1. Direct API Integration
Send events directly from your backend:
// Node.js example
const bizSdk = require('facebook-nodejs-business-sdk');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const access_token = 'YOUR_ACCESS_TOKEN';
const pixel_id = 'YOUR_PIXEL_ID';
const userData = (new UserData())
.setEmail('customer@example.com')
.setPhone('1234567890')
.setClientIpAddress(request.ip)
.setClientUserAgent(request.headers['user-agent']);
const serverEvent = (new ServerEvent())
.setEventName('Purchase')
.setEventTime(Math.floor(Date.now() / 1000))
.setUserData(userData)
.setCustomData({ value: 99.99, currency: 'USD' })
.setEventId('purchase_12345'); // For deduplication
const eventsData = [serverEvent];
const eventRequest = (new EventRequest(access_token, pixel_id))
.setEvents(eventsData);
eventRequest.execute();
2. Partner Integrations
Many platforms have built-in CAPI support:
- Shopify: Native CAPI in Meta channel app
- WooCommerce: Facebook for WooCommerce plugin
- Magento: Meta Business Extension
- BigCommerce: Meta Pixel app with CAPI
3. Gateway Services
Third-party services that handle CAPI:
- Segment: Events API to Meta CAPI
- Google Tag Manager Server-Side: CAPI template
- Stape: Dedicated CAPI hosting
- Tealium: Server-side connector
Required Parameters
User Data (for matching)
At least one of these for effective matching:
| Parameter | Hashing | Notes |
|---|---|---|
em |
SHA256 | Email address |
ph |
SHA256 | Phone number |
fn |
SHA256 | First name |
ln |
SHA256 | Last name |
ct |
SHA256 | City |
st |
SHA256 | State |
zp |
SHA256 | Zip code |
country |
SHA256 | Country code |
external_id |
SHA256 | Your customer ID |
Event Parameters
| Parameter | Required | Description |
|---|---|---|
event_name |
Yes | Standard or custom event name |
event_time |
Yes | Unix timestamp |
action_source |
Yes | website, app, email, etc. |
event_id |
Recommended | For deduplication |
event_source_url |
Recommended | Page URL |
user_data |
Yes | Customer identifiers |
Deduplication
When using both Pixel and CAPI, prevent double-counting:
// Generate unique event ID
const eventId = 'purchase_' + Date.now() + '_' + Math.random();
// Browser: include in pixel event
fbq('track', 'Purchase', { value: 99.99 }, { eventID: eventId });
// Server: include same ID in CAPI
serverEvent.setEventId(eventId);
Meta will automatically deduplicate events with matching event_id values received within 48 hours.
Event Match Quality (EMQ)
Track your matching effectiveness in Events Manager:
- Great (8-10): Excellent match rate
- Good (6-7): Acceptable performance
- OK (4-5): Room for improvement
- Poor (1-3): Likely missing key parameters
Improving EMQ
- Send more user data parameters
- Ensure data is correctly formatted
- Hash values properly (lowercase, trim whitespace)
- Include IP address and user agent from browser
Testing
Events Manager Test Events
- Go to Events Manager → Test Events
- Use the test event tool to send CAPI events
- Verify events appear with correct parameters
Debugging
Check the API response for errors:
eventRequest.execute()
.then(response => {
console.log('Events received:', response.events_received);
console.log('Messages:', response.messages);
})
.catch(error => {
console.error('CAPI Error:', error);
});