Server-Side Marketing Pixels
Implement Meta CAPI, Google Ads, LinkedIn, and other advertising pixels through your server-side container for improved conversion tracking accuracy.
Why Server-Side for Advertising?
Data Recovery Rates
| Platform | Client-Side Loss | Server-Side Recovery | |----------|------------------|---------------------| | Meta (Facebook) | 30-50% | +25-40% conversions | | Google Ads | 15-25% | +10-20% conversions | | LinkedIn | 25-35% | +15-25% conversions | | TikTok | 35-45% | +20-30% conversions |
Benefits by Platform
- Meta CAPI: Required for optimization post-iOS 14.5
- Google Ads: Enhanced conversions with first-party data
- LinkedIn: Better B2B attribution
- All Platforms: Deduplication, data enrichment, consent control
Meta Conversions API (CAPI)
Architecture
┌─────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Browser │────▶│ Server-Side │────▶│ Meta CAPI │
│ Pixel │ │ Container │ │ Endpoint │
└─────────────┘ └─────────────────┘ └─────────────┘
│ │
│ ▼
│ ┌───────────────┐
└───────────▶│ Deduplication │
│ (event_id) │
└───────────────┘
Prerequisites
- [ ] Meta Business Manager access
- [ ] Facebook Pixel configured
- [ ] System User access token
- [ ] Server-side container deployed
Step 1: Generate Access Token
- Go to Meta Business Suite > Events Manager
- Select your Pixel
- Navigate to Settings > Conversions API
- Click Generate Access Token
- Copy and securely store the token
Step 2: Configure Server Container
Create a Meta Conversions API tag:
| Setting | Value | |---------|-------| | Pixel ID | Your Pixel ID (15-16 digits) | | Access Token | System User token | | Action Source | website |
Step 3: Event Mapping
// Data layer event
dataLayer.push({
event: 'purchase',
event_id: 'evt_' + Date.now() + '_' + Math.random(),
ecommerce: {
transaction_id: 'T12345',
value: 99.99,
currency: 'USD',
items: [{
item_id: 'SKU_001',
item_name: 'Product Name',
price: 99.99,
quantity: 1
}]
},
user_data: {
email_hash: 'SHA256_HASHED_EMAIL',
phone_hash: 'SHA256_HASHED_PHONE'
}
});
Step 4: Configure Event Parameters
Map these parameters in your Meta tag:
| Meta Parameter | Source Variable | |----------------|-----------------| | event_name | Event Name | | event_time | Timestamp | | event_id | Event ID (for dedup) | | event_source_url | Page URL | | user_data.em | Hashed Email | | user_data.ph | Hashed Phone | | user_data.client_ip_address | IP Address | | user_data.client_user_agent | User Agent | | custom_data.value | Transaction Value | | custom_data.currency | Currency Code | | custom_data.content_ids | Product IDs |
Step 5: Deduplication
Critical: Use the same event_id in both browser pixel and CAPI:
// Generate once, use for both
const eventId = 'evt_' + Date.now() + '_' + Math.random().toString(36);
// Browser Pixel (via GTM web)
fbq('track', 'Purchase', {...}, {eventID: eventId});
// Server-side (via data layer)
dataLayer.push({
event: 'purchase',
event_id: eventId,
// ... other params
});
Verification
Check in Events Manager > Test Events:
- Events showing "Server" source
- Match rates for user data
- Deduplication working (no duplicates)
Google Ads Enhanced Conversions
Server-Side Setup
Enhanced conversions can be sent via server-side for better accuracy:
// Data layer with user data
dataLayer.push({
event: 'purchase',
transaction_id: 'T12345',
value: 99.99,
currency: 'USD',
enhanced_conversion_data: {
email: '[email protected]', // Will be hashed
phone_number: '+15551234567',
first_name: 'John',
last_name: 'Doe',
street: '123 Main St',
city: 'San Francisco',
region: 'CA',
postal_code: '94105',
country: 'US'
}
});
Server Container Configuration
- Create Google Ads Conversion Tracking tag
- Enable Include user-provided data
- Map user data variables
| Google Ads Field | Variable | |------------------|----------| | Conversion ID | AW-XXXXXXXXX | | Conversion Label | XXXXXXXX | | Conversion Value | Value variable | | Transaction ID | Transaction ID variable | | Email | Enhanced conversion email | | Phone | Enhanced conversion phone |
Hash Handling
GTM server-side will automatically hash plain-text user data. You can also pre-hash client-side:
// SHA-256 hashing function
async function hashValue(value) {
const normalized = value.toLowerCase().trim();
const encoder = new TextEncoder();
const data = encoder.encode(normalized);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
LinkedIn Conversions API
Setup Process
- Create Conversion in LinkedIn Campaign Manager
- Generate API Token for server-side access
- Configure Tag in server container
Server Container Tag
| Setting | Value | |---------|-------| | Conversion ID | Your conversion ID | | Partner ID | LinkedIn Partner ID | | Access Token | API access token |
Event Mapping
dataLayer.push({
event: 'lead_generated',
linkedin_conversion: {
conversion_id: '12345678',
value: 100,
currency: 'USD'
},
user_data: {
email_hash: 'SHA256_HASH',
linkedin_member_id: 'member_id_if_available'
}
});
TikTok Events API
Configuration
- Get Pixel ID and Access Token from TikTok Events Manager
- Create TikTok Events API tag
Event Parameters
| TikTok Parameter | Description | |------------------|-------------| | event | Event name (CompletePayment, etc.) | | event_id | For deduplication | | timestamp | Unix timestamp | | properties.value | Conversion value | | properties.currency | Currency code | | user.email | Hashed email | | user.phone | Hashed phone |
Multi-Platform Strategy
Unified Data Layer
Create a consistent data layer for all platforms:
// Universal purchase event
dataLayer.push({
event: 'purchase',
event_id: generateEventId(),
transaction: {
id: 'T12345',
value: 99.99,
currency: 'USD',
tax: 8.00,
shipping: 5.99
},
items: [{
id: 'SKU_001',
name: 'Product Name',
category: 'Category',
price: 85.00,
quantity: 1
}],
user: {
email: '[email protected]',
phone: '+15551234567'
}
});
Server-Side Distribution
One event triggers multiple platform tags:
Data Layer Event
│
▼
┌──────────────────┐
│ Server Container │
└────────┬─────────┘
│
┌────┴────┬─────────┬──────────┐
▼ ▼ ▼ ▼
┌─────┐ ┌──────┐ ┌────────┐ ┌──────┐
│ GA4 │ │ Meta │ │ Google │ │ etc. │
│ │ │ CAPI │ │ Ads │ │ │
└─────┘ └──────┘ └────────┘ └──────┘
Debugging
Meta Events Manager
- Go to Test Events tab
- Look for events with "Server" badge
- Check Match Quality score
- Verify deduplication status
Google Ads
- Use Conversion Diagnostics
- Check for "Enhanced" badge
- Verify match rates
Common Issues
| Issue | Cause | Solution | |-------|-------|----------| | Low match rate | Missing user data | Add more identifiers | | Duplicates | Missing event_id | Implement deduplication | | Missing events | Consent blocking | Check consent mode | | Wrong values | Variable mapping | Verify data layer |
Previous: Implementation Guide Next: Server-Side Troubleshooting