Tracking & Attribution

How Do Ad Blockers Break Conversion Tracking?

Ad blockers stop the pixel request before it is sent, so the conversion never fires. Here is exactly what breaks, and which signals still survive.

Quick answer

Ad blockers break conversion tracking at the network layer, not in your code. A filter list matches the tracking script's filename or the ad platform's collection endpoint, and the browser never sends the request — so the conversion event never fires. The visitor still browses, still types into your form, still buys. What survives is whatever your own server saw: the click ID in the landing URL, the contact details typed into the form, the order in your back office. Those can be sent to the platform server-to-server, a path no browser extension can reach.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Ad blockers break conversion tracking by stopping the request, not by breaking your code. A filter list matches the tracking script’s filename or the ad platform’s collection endpoint, and the browser never sends it. The visitor still browses, still fills in your form, still buys — but no client-side event ever fires, so the platform never learns the conversion happened.

This is the part that catches people out: there is no error. The page renders, the checkout completes, your tag assistant says the setup is healthy. The only symptom is a number that is quietly too low, in a report you have no reason to distrust.


What does an ad blocker actually block?

Individual network requests, chosen by pattern. A blocker ships a filter list of rules, each one matching a domain, a path, or a filename. When the page asks for a matching URL, the extension cancels the request before it leaves the browser.

The rules are public, so you can read exactly what happens to your stack. EasyPrivacy — the tracking list that ships enabled by default in uBlock Origin and AdGuard — carries these entries:

||facebook.com/tr/
||facebook.com/tr?
||connect.facebook.net/signals/$third-party
||analytics.tiktok.com^
||ct.pinterest.com^
||bat.bing.com^

The first two matter most. facebook.com/tr is the Meta Pixel’s collection endpoint — the URL every browser-side event is sent to. Blocking it means the pixel can load, initialise, and fire perfectly, and still deliver nothing. Every platform in that list loses its browser-side path the same way.

The same list also blocks the script by filename, regardless of who serves it:

/fbevents.js
/fbevents.min.js
/facebook_fbevents.js
/facebook-pixel.js
/fbpixel.js

Those rules have no domain attached. They match any host, which is the detail that defeats most workarounds.

Blockers do not always cancel the request outright. uBlock Origin’s privacy list replaces some scripts with a stub instead:

||google-analytics.com/analytics.js$script,xhr,redirect=google-analytics_analytics.js:5

The redirect= option substitutes a neutered local file that defines the expected functions and does nothing with them. Your page keeps working, your console stays clean, and your analytics receives nothing.

Diagram of a browser-side pixel request cancelled by a filter list beside a server-side conversion dispatch that succeeds, drawn in the PartialLeads dashboard style


Why does blocked tracking look like it is working?

Because every piece of feedback you have about your tracking is generated in a browser — usually yours, usually without a blocker. A blocked visitor produces no error you can see: no failed request in your logs, because the request was never made, and no exception, because nothing threw.

The three checks people trust all share that flaw. A pixel-helper extension inspects the page you are on. A test conversion is a conversion you performed. Real-time event views show the events that arrived, never the ones that did not.

Downstream, the failure arrives disguised as insight. Conversions firing with no click data land in the unattributed bucket, which is much of why ad conversions show as Direct more often than media buyers expect. Blocked visitors who convert never reach that bucket — they are absent, and absence is not a line item anywhere.


What does a blocked visitor still do on your site?

Everything except emit client-side events — which is the distinction worth internalising, because it separates the parts of your measurement that die from the parts that do not.

A visitor running uBlock Origin still clicks your ad, so the click ID still arrives in your landing page URL. Their browser still requests your pages from your server, with an IP address and user agent attached. They still type an email and a phone into your form, submit it or abandon it, and still pay — and that order lands in Shopify, WooCommerce, Stripe or your CRM with their email on it.

Every one of those facts is created on your infrastructure. None of them requires the ad platform’s script to run. That is the whole basis of first-party attribution, and it is why a blocked visitor is a measurement problem rather than a measurement dead end.


How do you measure how much of your traffic blocks tracking?

Compare a count only your server can produce against the same count from the browser, over the same window. You do not need a published industry average, and should not trust one — blocking rates vary sharply by audience, geography and device, and the only number that changes your decisions is yours. Three comparisons, cheapest first:

  1. Orders versus browser-side purchase events. Take the order count from your store admin for one week, and the purchase count the ad platform’s pixel recorded for the same week in your own timezone. The shortfall is your blocked-and-lost tail, plus anything the pixel dropped for other reasons.
  2. Server pageviews versus pixel pageviews. Your server or CDN logs every page request; your analytics logs the ones where its script ran. The ratio is your blocking rate, subject to bots inflating the server side.
  3. Form submissions in your database versus lead events in the ad platform. The same comparison, for lead gen.

Run all three before concluding anything. A gap in one comparison and not the others usually means a tagging bug rather than blocking. If iOS and Safari traffic carry most of the shortfall, you are looking at a browser-privacy gap as much as an extension one — auditing your iOS attribution gap separates those two causes properly.


Does self-hosting or proxying the pixel get around a blocker?

Partly, and less than the guides suggest. The three common workarounds each have a documented counter.

Serving the script from your own domain defeats domain-level rules, and runs straight into the filename rules quoted above. /fbevents.js has no domain attached; it matches your copy too. Renaming the file helps until the name is added, which is why that list of variants exists.

Routing events through a tagging server on your own subdomain is more durable, because the collection request goes to your hostname rather than facebook.com/tr. That is the real advantage of a server-side container. It is also an arms race: blocklists add rules for hosted tagging providers and the subdomain patterns they use, and a first-party endpoint that exists only to forward data to a tracker is a recognisable pattern.

Both still start in the browser. A tagging server does not help a visitor whose blocker stopped the script that would have called it. That is the ceiling on every client-side workaround: they change where the data goes, not whether anything runs.


What still works when the pixel never loads?

The server-to-server path. Instead of asking the visitor’s browser to report the conversion, your server reports it directly to the ad platform’s API — Meta’s Conversions API, and its equivalents at Google, Pinterest, TikTok and Microsoft. Meta documents the Conversions API as a way to send events directly from your server, and it is the supported route precisely because browser-side delivery is unreliable.

A browser extension cannot intercept a request between your server and Meta’s. It is not in the path, and it has no visibility into it.

What you give up is identifiers, not delivery. A server event is matched to a person using the parameters you attach: hashed email, hashed phone, the _fbp and _fbc browser cookies, IP address, user agent, and your own external ID. Meta’s documentation ranks hashed email as the highest-weight identifier. The two cookie values are collected client-side — so for a blocked visitor they are simply missing, and event match quality is scored on a thinner payload.

One of the two is recoverable. _fbc is derived from the fbclid parameter in your landing URL, which your server received directly and can reconstruct in Meta’s documented format. _fbp has no equivalent: it is a value the pixel generates in the browser, and if the pixel never ran there is nothing to recover. Anyone claiming otherwise is fabricating an identifier.

This is also why the pixel and the Conversions API are not alternatives. Keep the browser tag for the visitors who allow it — it supplies cookies your server payload cannot invent — and let the server path carry everyone else. Meta’s deduplication rules mean the overlap costs you nothing: events sharing an event_id and event name are collapsed into one.


Can ad blockers block server-side conversion tracking too?

Not the dispatch. They can still reduce what it knows.

Split the problem in two. Delivery is whether the event reaches the ad platform at all; it happens between two servers, and no browser extension participates. Matching is whether the platform can tie that event to a real person and an ad click; it depends on the identifiers in the payload and on the platform’s own ability to resolve them.

Blocking damages the second half only, and only for the identifiers that originate in the browser. A blocked buyer whose email you captured still produces a matched conversion. A blocked buyer you know nothing about produces a delivered event with weak identifiers — worth more than the nothing you had, worth less than a full payload.

What can still hurt delivery is your own capture layer. Any script served to a browser can be blocked, including the one that records form input. Public tracking lists carry no rules for PartialLeads today, but no vendor should promise that about a list anyone can add a line to. The structural answer is to not depend on it: when conversions fire from order and lead records on the server, a visitor whose script never loaded still produces a conversion event the moment their order arrives.


How does PartialLeads keep conversions flowing when the pixel is blocked?

By moving both halves of the job off the browser. The Conversions API dispatch runs from PartialLeads’ server against your purchase and lead records, so the event does not depend on the visitor’s browser cooperating at the moment of conversion.

The mechanics, specifically:

  • The visitor ID cookie is set by the server, not written by JavaScript, with localStorage as backup. Safari’s restrictions on script-written cookies do not apply to it, so returning visitors stay stitched to the same person.
  • Click IDs are captured from the landing requestfbclid, gclid, gbraid, wbraid, msclkid, ttclid and epik — and stored server-side against the session. When the _fbc cookie is missing or malformed, the backend reconstructs it from the URL fbclid in Meta’s documented format. The URL is treated as the source of truth.
  • Email and phone are captured as they are typed, before submit, then normalised — email lowercased and trimmed, phone to E.164 — and hashed per platform spec. These are the highest-weight match parameters, and they come from your form rather than from any cookie.
  • Purchases arrive server-to-server from Shopify, WooCommerce, Stripe, GoHighLevel or a universal webhook, are matched to a session by visitor ID, email, phone or IP in that order of confidence, and fan out to the connected conversion APIs.
  • Every dispatch carries a deterministic event_id — a hash of the pixel, event name and record — stored in a uniqueness-constrained dedup table. A redelivered webhook or a retried send cannot double-count, and browser-side events sharing that ID collapse into one on the platform’s side.

The honest constraint is the same one that applies to every vendor: keep your client-side base tag installed. The platform cookies it sets are match parameters no server can synthesise, and PartialLeads reconstructs _fbc but never invents _fbp. With email and phone as required fields, PartialLeads consistently delivers EMQ 9+, observed across customer accounts — that condition is load-bearing, because an email-only form structurally caps the score no matter what the dispatch layer does.

Where you watch it work: the CAPI activity log shows every send with its status, platform and match quality, and the Leads list carries a per-lead API column naming which conversion APIs that lead was dispatched to. The Attribution report’s revenue-by-match-quality donut splits net revenue into partial-captured, submit-completed and unmatched — the closest thing to a direct read on what a browser-only setup would have missed.

Mockup of the PartialLeads CAPI activity log showing server-side conversion sends with status dots, platform chips, match quality values and a delivery health strip

The claim worth being precise about: every order in your store admin produces a conversion event, because the send is triggered by the order record rather than by a browser. You can verify that yourself by reconciling your admin order count against dispatched events. Whether the platform then matches each event to a user is decided by the identifiers you collected and by the platform’s own graph — that half is maximised, never guaranteed, and no tool controls it.

What breaks The mechanism Where you see it in the dashboard
Pixel script blocked by filename rule Server-side dispatch from lead and order records, independent of the browser CAPI activity log, sends with no matching browser event
Collection endpoint blocked, pixel fires into nothing Conversions API send from PartialLeads’ server to the platform API CAPI activity log status column
_fbc cookie missing for a blocked visitor _fbc reconstructed from the landing URL fbclid in Meta’s format Per-lead click ID fields, CAPI payload
Cookie cleared or capped, returning visitor looks new Server-set visitor ID cookie plus localStorage backup Journey ribbon showing multiple sessions per person
Conversion arrives with no identifiers Email and phone captured before submit, normalised and hashed Match rate KPI, revenue by match quality donut
Purchase never reported because the tab closed Purchase webhook matched to the session server-side Purchases ledger, matched wedge
Retries and redelivered webhooks double-count Deterministic event_id plus uniqueness-constrained dedup table CAPI activity log, single row per event
No idea whether a specific lead was sent Per-lead dispatch record Leads list API column

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Sources

  1. EasyPrivacy third-party filter list (rules for facebook.com/tr, connect.facebook.net/signals, analytics.tiktok.com, ct.pinterest.com, bat.bing.com): https://raw.githubusercontent.com/easylist/easylist/master/easyprivacy/easyprivacy_thirdparty.txt
  2. EasyPrivacy general filter list (filename rules /fbevents.js, /fbevents.min.js, /facebook_fbevents.js, /facebook-pixel.js, /fbpixel.js): https://raw.githubusercontent.com/easylist/easylist/master/easyprivacy/easyprivacy_general.txt
  3. uBlock Origin privacy filter list (redirect= surrogate substitution for google-analytics.com/analytics.js): https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/privacy.txt
  4. Meta for Developers — Conversions API overview: https://developers.facebook.com/docs/marketing-api/conversions-api
  5. Meta for Developers — Conversions API, customer information parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
  6. Meta for Developers — Conversions API, fbp and fbc parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc
  7. Meta for Developers — Deduplicate Pixel and Conversions API events: https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events
  8. Meta Business Help Centre — About event match quality: https://www.facebook.com/business/help/765081237991954

Frequently asked questions

QWhat percentage of my visitors block conversion tracking?
Nobody can tell you from the outside, and published averages hide enormous variance by audience, country and device. Measure it: compare your store admin's order count against the ad platform's browser-recorded purchases for the same week, and your server's pageview count against your analytics pageviews. Run both before drawing a conclusion, because a gap in only one usually means a tagging bug rather than blocking.
QDoes an ad blocker stop the Meta Pixel from loading, or just from sending?
Both, through separate rules. EasyPrivacy carries filename rules like `/fbevents.js` that stop the script loading from any host, and a rule for `facebook.com/tr` that blocks the collection endpoint the pixel posts events to. The second is the nastier failure, because the pixel can initialise and fire normally while every event it sends is cancelled.
QWill serving the pixel from my own domain fix it?
Not on its own. The filename rules have no domain attached, so a self-hosted copy of `fbevents.js` matches them too, and renaming the file works until the new name is added to a list. Routing events through a tagging server on your own subdomain is more durable, but it cannot help a visitor whose blocker prevented the script from running in the first place.
QCan ad blockers block the Conversions API?
No. A browser extension can only act on requests the browser makes. A server-to-server call from your backend to Meta's API is not in its path. What blocking still costs you is identifiers that originate in the browser — the `_fbp` and `_fbc` cookies — so the event is delivered but matched on a thinner payload.
QIf I send conversions server-side, can I remove my pixel?
You should not. The base tag collects the platform's own browser cookies, which are match parameters your server payload cannot invent. Removing it lowers match quality for every visitor who was not blocking anything. Run both and rely on deduplication: events sharing an event ID and event name are collapsed into one, so the overlap does not inflate your numbers.
QCan a tool recreate the `_fbp` cookie for a blocked visitor?
No, and treat any claim that it can as a red flag. `_fbc` is different — it derives from the `fbclid` parameter in your landing URL, which your server received directly, so it can be legitimately reconstructed. `_fbp` is generated by the pixel inside the browser. If the pixel never ran, the value never existed and inventing one fabricates an identifier.
QDo ad blockers affect lead-gen forms as much as ecommerce?
Often more, because lead gen usually has fewer server-side records to fall back on. An ecommerce store always has an order in its admin; a lead-gen site whose only record of the conversion is a browser event has nothing left when that event is cancelled. Capturing form input server-side, before submit, is what gives lead gen the same fallback a store gets from its order table.
QDoes blocking explain why my ad platform reports more conversions than my CRM?
Usually not — that gap normally runs the other way, and is caused by attribution windows, view-through crediting and modelled conversions rather than by blocking. Blocking makes the platform report fewer conversions than actually happened. If the platform is reporting more than your own records, investigate windows and deduplication first.
QIs there any way to track a blocked visitor who never identifies themselves?
Only in aggregate. You still see their pages from your own server logs and the click ID from their landing URL, so the traffic and the campaign are visible. Tying a specific later purchase to that specific click, though, needs a shared identifier — a cookie you set, or contact details they typed. With neither, the honest answer is that the join cannot be proven.

Find the qualified leads your forms are currently throwing away.

Install PartialLeads on one landing page, send traffic, and compare what your CRM captured against what PartialLeads recovered and qualified.