Skip to content
Academy
Marketing Academy · Field Work●Analytics & Attribution
CoreAudit· 35 minutes

The Missing 18%: Auditing a Client vs Server Event Gap

Chewy

Objective: Given a one-week export comparing GA4 (client-side) purchase counts to Google Ads-reported conversions, segmented by browser, diagnose where the tracking gap is coming from and which fix to prioritize.

You're the analytics lead at Chewy. The paid-search team flags that Google Ads reports 18% more purchases this week than GA4 shows, and wants to know if their campaigns are actually working or if the algorithm is optimizing on bad data.

Segment the gap by browser before you touch anything, and connect the pattern to a specific cause the lesson names (ITP, ad blockers, or both), not a vague 'tracking is broken.'

Before you start

What you'll need

Free path (everything below is enough to finish)

FreePivot the browser-segmented export and calculate gap percentages

Free, no account friction, sufficient for a one-week diagnostic pivot

Paid upgrades (optional, faster/deeper)

Segment(optional)
FreemiumCentralize event collection with built-in deduplication once volume outgrows manual event_id checks

Handles event_id matching and multi-destination forwarding at scale

No access? Manual event_id spot-checks in Google Sheets, as done in this project

The process

2 steps

Step 01 of 02

Diagnosing a client-side tracking gap by browser segment

The lesson names three forces killing browser-side tracking: Safari's ITP caps JS-set cookies at 7 days, ad blockers strip tracking scripts outright, and iOS ATT suppresses in-app signals. Each leaves a different fingerprint in a browser breakdown.

The export shows Safari accounts for 61% of the missing purchases despite being only 19% of sessions. Chrome and Firefox are roughly in line with their session share. What's actually happening here?

Google Sheets— Import weekly-event-export.csv, pivot purchases by browser against Google Ads-reported conversions for the same browser.

Procedure

  1. Import weekly-event-export.csv and freeze the header row
  2. Build a pivot table: browser (rows) vs. GA4 purchases and Ads-reported purchases (columns)
  3. Add a 'gap %' column: (Ads reported - GA4) / Ads reported
  4. Sort by gap % descending to find the worst-offending browser segment
Sample output
Browser    Sessions%   GA4 Purchases   Ads-Reported   Gap %
Safari     19%         142              365            61%
Chrome     58%         890              945             6%
Firefox    12%         210              228             8%
Edge       11%         180              190             5%

Healthy

The gap concentrates almost entirely in Safari, a clean signature of ITP cookie expiry, and the fix is a first-party subdomain, not a full sGTM rebuild for every platform at once.

Unhealthy

The gap is spread evenly across all browsers, which points to a missing or misconfigured base tag, not a privacy-rule problem, and no amount of server-side migration fixes a broken pixel.

What this means

A gap concentrated in one browser tells you which mechanism is responsible; a gap spread evenly tells you the problem is upstream of privacy rules entirely.

So what do I do about it?

SymptomActionEffort
Safari carries 3x its session share of the missing purchasesPrioritize the first-party subdomain + server-set cookies fix before adding server tags for every ad platformdev ticket
The gap is evenly spread across all browsersAudit the base GA4 tag firing conditions before assuming a privacy-rule cause30 min
YouYou can do this yourself, no engineering access required.

Step 02 of 02

Event deduplication with a shared event_id

The lesson calls event_id deduplication the step most teams get wrong: send a matching event_id from both the browser pixel and the server tag, or every purchase gets counted twice.

A second export shows Meta Ads Manager reporting 512 purchases while Shopify's order log shows 260 real orders for the same week. What single missing field explains a number almost exactly double?

Google Sheets— Compare the event_id column across the browser-pixel export and the server-tag export.

Procedure

  1. Filter the browser-pixel export for event_id values
  2. Filter the server-tag export for event_id values on the same date range
  3. Check whether any event_id appears in only one of the two exports (a shared ID means dedup is working)
  4. Count events with no event_id at all, these can never be deduplicated
Sample output
event_id present in BOTH exports: 0 of 260
event_id present in browser export only: 260
event_id present in server export only: 252
Total reported to Meta: 512 (260 + 252)
Actual Shopify orders: 260

Healthy

Every real purchase has one shared event_id appearing in both the browser and server payload, so Meta discards the duplicate and reports 260, matching Shopify.

Unhealthy

Zero event_ids match between browser and server payloads, meaning Meta treats every purchase as two separate events, exactly the 2x inflation the lesson warns about.

What this means

A reported number that's almost exactly double the real order count is the signature of missing deduplication, not fraud or a tracking gain.

So what do I do about it?

SymptomActionEffort
Ad-platform reported conversions run ~2x actual order volumeAdd a shared event_id (e.g. order ID) to both the browser pixel and server tag payloads for the same eventdev ticket
DeveloperNeeds a developer/engineer to ship the fix.

Final deliverable

A one-page diagnostic memo naming which browser segment drives the majority of the gap, whether deduplication is working, and the single highest-priority fix.

See a reference example
Sample output
Robinhood, Paid Search Tracking Diagnostic (excerpt)

FINDING 1: Safari carries 58% of the missing conversions on 19% of sessions, ITP cookie expiry.
FINDING 2: event_id is present in both browser and server payloads for 100% of sampled purchases, deduplication is healthy.
RECOMMENDATION: Ship the first-party subdomain fix this sprint; no action needed on deduplication.

Success criteria

You're done when you can:

  • Correctly isolates which browser segment carries the disproportionate share of the gap
  • Distinguishes an ITP/ad-blocker signature from a broken-base-tag signature
  • Correctly diagnoses whether a 2x reported-vs-actual pattern is a deduplication failure