You implement Meta’s Conversions API (server-side) alongside your existing Meta Pixel (browser-side) for better iOS tracking. Then you notice your Meta Ads conversion count doubles. This is event duplication: both the browser pixel and your server are sending the same purchase event to Meta. Without proper deduplication, Meta counts each one separately, inflating ROAS and corrupting your bidding algorithm. This guide explains exactly how to implement event_id deduplication correctly.

Why Duplication Happens

When you set up both browser pixel and server-side Conversions API for the same conversion event (e.g., Purchase), you now have two systems sending the same event to Meta:

  • Browser pixel fires when the thank-you page loads in the user’s browser
  • Server sends a Conversions API event when your backend confirms the order
  • Meta receives two Purchase events for the same order
  • Without deduplication: Meta counts 2 conversions, reports inflated ROAS

The Solution: event_id Parameter

Meta uses the event_id parameter to deduplicate events. If two events arrive with the same event_id within 48 hours, Meta counts them as one event.

// Browser Pixel (fires on thank-you page)
const orderId = 'order_789';  // Your unique order ID
const eventId = 'purchase_' + orderId;  // Unique, deterministic event ID

fbq('track', 'Purchase', {
  value: 119.98,
  currency: 'USD',
  order_id: orderId
}, {
  eventID: eventId  // THIS is the deduplication key
});

// Server-side Conversions API (fires from backend)
const serverPayload = {
  data: [{
    event_name: 'Purchase',
    event_id: eventId,  // SAME event_id as browser pixel
    event_time: Math.floor(Date.now() / 1000),
    user_data: {
      em: [SHA256(customer.email)],
      ph: [SHA256(customer.phone)]
    },
    custom_data: {
      value: 119.98,
      currency: 'USD',
      order_id: orderId
    }
  }]
};

// Meta sees eventID matches → counts as ONE conversion

Generating Unique, Deterministic event_ids

The event_id must be unique per event instance and the same on both browser and server. Using the order ID as part of the event_id is the most reliable approach for purchase events.

Meta Pixel Deduplication: How Server-Side and Browser Events Firing Twice Inflate Conversions
// For purchase events: use order ID
const eventId = 'purchase_' + orderId;

// For lead events: use a form submission ID or session + timestamp
const eventId = 'lead_' + sessionId + '_' + Date.now();

// Pass event_id to both browser and server
// Store event_id in your session/database so server can use same value

// In practice: generate event_id when user clicks submit,
// store in hidden field or session, send to server on form submit
const eventId = 'lead_' + crypto.randomUUID();
document.getElementById('event_id_field').value = eventId;

// Browser fires pixel immediately:
fbq('track', 'Lead', {}, {eventID: eventId});

// Server receives eventId with form data and sends CAPI with same ID

Verifying Deduplication Is Working

  • Go to Meta Events Manager → Events → your Purchase event
  • Check “Deduplication” tab — it shows how many events were deduplicated vs unique
  • If you see 0% deduplication rate with server + browser both enabled, event_ids aren’t matching
  • Expected deduplication rate: 60-90% (some server events won’t have a browser counterpart due to iOS opt-outs)

What Happens Without Deduplication

  • Conversion count inflates 2x
  • ROAS appears double what it actually is
  • Meta’s bidding algorithm optimizes based on wrong signal density
  • Budget may shift away from channels that are actually performing

Always implement event_id deduplication before deploying Conversions API alongside an existing browser pixel. Test it with Meta’s Event Testing Tool before going live.

Related guides: Meta Conversions API Field Mapping, Meta Ads Attribution Window, Server-Side vs Client-Side GTM Latency.

Guide: Meta Pixel Deduplication: How Server-Side and Brow

Leave a Comment