by edwardglush | 2026-02-21 19:27:05+00:00
When a user buys something on your site, here's what actually happens:

Meta fires a Purchase event. Google fires a Purchase event. TikTok fires a Purchase event. All three claim 100% credit. Your dashboard says you had 3x the revenue you actually made. You make budget decisions based on this. You're wrong.

## The Mechanism

Standard ad pixels work like this:

```
User buys → browser fires gtag/fbq → outbound HTTP request → ad platform server
```

The problem is step 3. Ad blockers intercept at the network level. iOS ITP (Intelligent Tracking Prevention) purges client-side cookies after 7 days. Firefox Enhanced Tracking Protection blocks third-party requests entirely.

The result: your Meta pixel might be seeing 38% fewer purchase events than actually occurred. GA4 sees 16% fewer. You don't know, because you have no ground truth to compare against.

## The Harder Problem: Multi-Touch Attribution

Even if you recover 100% of signals, you still have the attribution problem. Meta, Google, and TikTok each run last-click (or self-serving multi-touch) models that claim 100% credit for every conversion they touched.

The reality: a user might have:
1. Clicked a TikTok ad 10 days later (Safari purges cookie at day 7 — that click is now untracked)
2. Bought via a Klaviyo email on day 21

Standard analytics attributes this to Klaviyo. Meta claims it because they got a view. TikTok's pixel is broken after the ITP purge. ChatGPT gets $0. Nobody knows what actually drove the sale.

## The Pre-Block Capture Pattern

One approach that actually works at the browser level: intercept pixel calls before they hit the network.

Most pixels attach to window globals. You can wrap these functions:

```javascript
const originalFbq = window.fbq;
window.fbq = function(...args) {
// Capture payload locally first
captureToFirstPartyServer(args);
// Then let the original call proceed (might get blocked, doesn't matter)
return originalFbq.apply(this, args);
};
```

By wrapping at the function level, you capture the raw payload the exact millisecond it's created — before any ad blocker can intercept the outbound request. You then forward it via your own first-party domain, which ad blockers can't block without breaking your site entirely.

This is the core of what Zyro (https://zyro.world) calls their "Omni-Interceptor" — but the pattern itself is straightforward to implement if you want to roll your own.

The wrapping loop should poll because some pixels initialize asynchronously:

```javascript
const huntingLoop = setInterval(() => {
if (window.fbq) {
wrapPixel('fbq', window.fbq);
clearInterval(huntingLoop);
}
}, 500); // Poll every 500ms, max 5 seconds
```

## Fractional Attribution Without Losing Your Mind

Once you have a reliable server-side event stream, you need a model that doesn't just credit the last touch.

For each session, record:
- Acquisition source (UTM params, referrer, fbclid, gclid, etc.)
- Behavioral engagement signals (time on page, scroll depth, adds to cart)
- Timestamp

On conversion, apply fractional credit weighted by recency and engagement. A touch 1 day before conversion at 80% scroll depth gets more credit than a view 30 days ago.

## 7-Day Benchmark Data

Running platform-reported vs. server-side verified conversions:

| Source | Platform Reports | Server Truth | Delta |
|--------|-----------------|--------------|-------|
| GA4 | 202 orders | 241 orders | -16% |
| Meta | 149 orders | 241 orders | -38% |

Meta's pixel is missing 38% of purchase events. You're making budget allocation decisions on data that misses a third of your conversions.

---

Discussion: Has anyone built their own pre-block capture layer? Curious what approaches others have taken for first-party attribution.

Further reading: Zyro (https://zyro.world) — the tool we built to solve this at scale, if you'd rather not DIY.