Published: Jul 14, 2026

· 10 min read
This article is also available in German: Deutsche Version

Event Deduplication for Meta CAPI and Google Analytics: How to Stop Double-Counting

20–40% of your reported conversions are likely duplicates. Fix event deduplication with event_id and cut CPA by 15–25%. Here's the exact pattern.

ON
Oleksandr Nikitin
Event Deduplication for Meta CAPI and Google Analytics: How to Stop Double-Counting

TL;DR: Without event deduplication, Meta and Google over-count your conversions by 20–40%. You’re making budget decisions on inflated numbers — and burning money without realizing it. The fix is a shared event_id parameter that links browser pixel and server event. For our client Erkado, correct deduplication (alongside CAPI and Advanced Matching) lifted EMQ from 3.2 to 8.7 and quadrupled ROAS from 1.2x to 4.7x.

Here’s a number that should make you uncomfortable: across 30+ account takeovers in the past 18 months, more than 80% of setups had either broken or completely missing deduplication. Eight out of ten advertisers are reporting conversions that never happened — and scaling budget based on those phantom numbers.

This isn’t a minor tracking glitch. It’s a systematic distortion of your entire performance dataset. If you’ve ever wondered why your CPAs “suddenly” rise when you scale spend, the answer often isn’t in your campaign structure. It’s in your tracking (Source: Canem Errant, account takeover data 2024–2026).

If you haven’t set up server-side tracking yet, start with our complete Server-Side Tracking Guide. This article builds on that foundation.

Why are Meta and Google counting your events twice?

The architecture is the problem. When you’ve implemented Meta CAPI correctly (and if you haven’t, our CAPI Setup Guide walks you through it), you’re sending the same event through two channels:

  1. Browser Pixel: JavaScript fires the event in the user’s browser.
  2. Server API: Your GTM Server Container sends the same event via the Conversions API.

Meta doesn’t automatically know that both events represent the same purchase. Without a shared identifier, Meta counts each pair as two separate conversions. One purchase becomes two. Ten purchases become twenty.

The same pattern exists in Google Analytics 4: if you fire a gtag.js purchase event AND send a Measurement Protocol hit for the same transaction without a shared transaction_id, GA4 counts the revenue twice.

Hot take: Double-counted conversions are worse than missing conversions. Missing conversions make you cautious — you scale slower but don’t waste money. Double-counted conversions make you overconfident. You scale based on a CPA that’s actually twice what you think it is. That’s the most expensive mistake in performance marketing, and we see it constantly.

What is event_id and how does deduplication actually work?

The event_id is a unique identifier that you generate once per event on your website and then send through both channels (Pixel + CAPI). Meta compares incoming events using the combination of event_name + event_id. When two events with identical event_id values arrive within 48 hours, Meta keeps one and discards the duplicate (Source: Meta Business Help Center — Deduplication).

For Google Analytics 4, the transaction_id serves the same role — but only for purchase events. GA4 automatically deduplicates transactions when the same transaction_id arrives multiple times within 24 hours (Source: Google Analytics Help — Duplicate Transactions).

PlatformDedup ParameterScopeTime WindowAutomatic?
Meta CAPIevent_idAll events48 hoursYes, if event_id is sent
GA4 (Measurement Protocol)transaction_idPurchase only24 hoursYes, if transaction_id matches
GA4 (gtag.js)transaction_idPurchase onlyWithin sessionYes

How do you implement the event_id pattern correctly?

The implementation has three parts: dataLayer push, GTM Web Container, GTM Server Container. Here’s the exact pattern we deploy for clients.

Step 1: Generate event_id in the dataLayer

The event_id must be generated on the website — not in GTM, not in the Server Container, not in Meta. The website is the single source of truth.

// On the Thank You / Order Confirmation page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'purchase',
  event_id: 'purchase_' + orderData.orderId + '_' + Date.now(),
  ecommerce: {
    transaction_id: orderData.orderId,
    value: orderData.total,
    currency: 'EUR',
    items: orderData.items
  },
  user_data: {
    email: orderData.email.toLowerCase().trim(),
    phone_number: orderData.phone, // E.164 format
    address: {
      first_name: orderData.firstName.toLowerCase(),
      last_name: orderData.lastName.toLowerCase(),
      postal_code: orderData.zip,
      country: 'AT'
    }
  }
});

Note that event_id is not the same as transaction_id. The event_id identifies a specific event firing (a single purchase can theoretically trigger multiple events — e.g., on page reload). The transaction_id identifies the business transaction itself.

Step 2: Pass event_id through the GTM Web Container

In the GTM Web Container, create a Data Layer Variable for event_id and send it with the Meta Pixel event:

  • Variable Name: DLV - event_id
  • Data Layer Variable Name: event_id
  • Set this value as the eventID parameter in the Meta Pixel tag

Step 3: Forward event_id in the GTM Server Container

The Server Container receives the event from the Web Container, including the event_id. In the Meta CAPI Tag within the Server Container:

  • Event ID: {{Event ID}} (automatically mapped from the incoming event)
  • The server sends the same event_id value to Meta — now Meta can match both events and deduplicate.

Key Takeaway: The event_id must be generated at exactly one place — the website. From there, it flows through both channels: Browser Pixel → Meta, and Website → GTM Server → CAPI → Meta. If you generate the event_id in two different places, the values are different by definition, and deduplication fails silently.

How do you deduplicate Google Analytics 4 transactions?

GA4 is simpler because the transaction_id does the heavy lifting. If you’re using both gtag.js and the GA4 Measurement Protocol (via your Server Container), make sure:

  1. Both events send the same transaction_id — the order ID from your shop system.
  2. No random suffixes — don’t append timestamps or UUIDs. The raw order ID is enough.
  3. Measurement Protocol events must include transaction_id in the params object.

When done correctly, GA4 recognizes the duplicate automatically and counts revenue only once. There’s no separate event_id mechanism like Meta uses — transaction_id is the sole dedup key.

What are the most common deduplication mistakes?

Across our account takeovers, we find the same patterns over and over. Here are the top five:

MistakeWhy It BreaksFrequency
No event_id sent at allPixel and CAPI fire blindly — Meta can’t deduplicate~40% of setups
event_id generated in GTM instead of the websiteWeb and Server containers generate different IDs~25%
Timestamp-only event_idDate.now() is identical for fast sequential requests but different with 100ms delay — unreliable~15%
Math.random() as event_idDifferent by definition every time — deduplication impossible~10%
event_id in Pixel only, not in CAPIOnly one channel sends the ID — Meta has no match partner~10%

The most common mistake — simply not sending an event_id at all — affects nearly half of all setups we inherit. This isn’t an edge case. It’s the norm.

How do you test whether your deduplication is working?

Meta provides the Test Events Tool in the Events Manager. Here’s how to use it:

  1. Open Events Manager → Your Pixel → “Test Events” tab
  2. Enter your website URL and click “Open Website”
  3. Trigger a purchase (or use a test event)
  4. In the Test Events tool, you should see two events: one from the browser (Pixel), one from the server (CAPI)
  5. Both must show the same event_id
  6. Meta displays the deduplication status in a dedicated column: deduplicated or not

If you see two Purchase events with different event_id values — or one without an event_id — your deduplication is broken.

For GA4: Use GA4 DebugView (Admin → DebugView). Check that purchase events with the same transaction_id are only counted once. If you see the same purchase twice in the Realtime report, something is wrong.

What happens to your numbers after you fix deduplication?

The truth hurts briefly: your reported conversions drop. For a typical setup without deduplication, we see reported conversions decline by 20–40% (Source: Canem Errant, aggregate data 2024–2026). That’s not data loss — it’s the phantom conversions that were inflating your numbers being stripped away.

What happens next is the real payoff: Meta gets clean data. The algorithm optimizes for real conversions instead of inflated phantom numbers. For Erkado (dvere-erkado.cz), the combination of correct deduplication, CAPI, and Advanced Matching drove EMQ from 3.2 to 8.7 — and ROAS climbed from 1.2x to 4.7x within 8 weeks (Source: Canem Errant Case Study).

In practice, we observe a CPA decrease of 15–25% within 4–6 weeks of fixing deduplication. Not because the ad budget changes, but because Meta finally optimizes on real signals instead of noise.

Hot take: If your CPA “rises” by more than 30% after implementing deduplication, you had a massive data quality problem before — and every budget decision you made in the past months was based on fiction. That’s not a tracking hiccup. That’s a strategic misallocation of capital, and the sooner you face the real numbers, the sooner you stop bleeding money.

Bottom Line: Over 80% of setups have broken or missing deduplication, inflating reported conversions by 20–40%. Fixing it drops CPA by 15–25% within 4–6 weeks because Meta finally optimizes on real signals instead of phantom numbers (Source: Canem Errant, 2026).

Frequently Asked Questions

What is event deduplication and why does it matter for Meta Ads?

Event deduplication prevents Meta from counting the same conversion twice when you run both the browser Pixel and Conversions API (CAPI). Without it, a single purchase shows up as two conversions — inflating your numbers by 20–40% and causing the algorithm to optimize on false data.

What is the difference between event_id and transaction_id?

The event_id identifies a specific event firing (used by Meta for deduplication across Pixel and CAPI). The transaction_id identifies the business transaction itself (used by Google Analytics 4 for deduplication). Both must be sent, but they serve different platforms and scopes.

Where should I generate the event_id — in GTM or on the website?

Always on the website, in the dataLayer push. If you generate it in GTM, the Web Container and Server Container produce different IDs, and deduplication fails silently. The website is the single source of truth — the event_id flows from there through both Pixel and CAPI channels.

How can I tell if my deduplication is broken?

Open Meta Events Manager → Test Events, trigger a purchase, and check that both the Pixel event and CAPI event show the same event_id. If the IDs differ or one is missing, deduplication is broken. Also compare server vs. browser event counts — if server events are roughly double the browser events, you have a problem.

Will fixing deduplication make my reported conversions drop?

Yes — reported conversions typically drop by 20–40% because phantom duplicates are stripped away. This is not data loss; it’s removing inflated numbers. Within 4–6 weeks, CPA drops 15–25% because Meta starts optimizing on real signals instead of noise.


We’ll review your event deduplication in a free 30-minute audit. No slide decks, no sales pitches — just straight talk and actionable recommendations. Request audit →

Ready to scale your performance marketing?

Explore our Services, check out our Case Studies, or schedule a free Discovery Call with us.

event-deduplicationMeta-CAPIgoogle-analyticstrackingserver-side