Skip to main content

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

  1. Go to Meta Business Suite > Events Manager
  2. Select your Pixel
  3. Navigate to Settings > Conversions API
  4. Click Generate Access Token
  5. 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

  1. Create Google Ads Conversion Tracking tag
  2. Enable Include user-provided data
  3. 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

  1. Create Conversion in LinkedIn Campaign Manager
  2. Generate API Token for server-side access
  3. 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

  1. Get Pixel ID and Access Token from TikTok Events Manager
  2. 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

  1. Go to Test Events tab
  2. Look for events with "Server" badge
  3. Check Match Quality score
  4. Verify deduplication status

Google Ads

  1. Use Conversion Diagnostics
  2. Check for "Enhanced" badge
  3. 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