AntiAdBlock.Core
Detection8 min readBy Marcus Holt

How ad blockers bypass detection scripts: and what publishers can do

Ad blockers do not just block ads, they also block the scripts that detect them. Here is how they evade publisher-side detection, and what evasion-resistant detection looks like.

What 'bypass adblock detection' means from both sides

When publishers search for bypass adblock detection, they often encounter two different conversations at once. One side is users: people running ad blockers who want to avoid anti-adblock walls publishers have installed. The other side is publishers: people whose detection scripts have mysteriously stopped working, and who need to understand why. This guide is the publisher's side, how ad blockers evade detection, and what to do about it.

The short answer is that modern ad blockers are actively maintained to defeat detection scripts, not just ads. They have dedicated mechanisms for neutralising publisher-side JavaScript that tries to observe them. Understanding those mechanisms is the prerequisite for building detection that holds up rather than silently degrading over weeks.

There are three main evasion paths: filter-listing the detection script so it never loads, exploiting Manifest V3 so the blocking leaves no observable JavaScript signal, and injecting scriptlets that neutralise the detection vectors the script does manage to run. Each requires a different counter-strategy.

Filter-listing: when the detection script never runs

The simplest evasion is filter-listing the detection script itself. EasyList, the uBlock Origin supplementary lists and the AdGuard supplement all maintain rules that target not just ad URLs but known anti-adblock scripts. Once your detection script's URL appears on a public filter list, the ad blocker simply prevents it from loading, and a detector that never loads reports nothing. From your dashboard, ad-block usage appears very low; in reality the detector is blocked.

Bait elements are equally exposed. A detection script that creates a div with a class name like ad-banner and checks whether the element was hidden is depending on a cosmetic filter applying. But if the class name is static and recognisable, a filter-list rule can be written to simply not apply cosmetic filtering to that specific bait, so the element stays visible, the detector sees no hiding, and reports no blocker.

The defence is a moving surface. Bait element classes and IDs should be randomised on every page load, not static strings any list maintainer can copy into a rule. The detection script itself should be served from a signed, origin-locked, non-predictable path rather than a publicly known URL. Static targets get listed; randomised targets cannot be captured by a fixed rule.

Manifest V3 and blocking below the page

Chrome's Manifest V3 introduced declarativeNetRequest, which moves the blocking decision from extension JavaScript into the browser's native network layer. uBlock Origin Lite, the MV3 successor to classic uBlock Origin, blocks entirely at this level. It never runs JavaScript in the page, never touches the DOM, and never fires any event the page can observe, it simply prevents certain requests from completing before the page ever knows they were made.

This is a direct bypass of the DOM-bait detection pattern. A bait element whose src points to an ad path will not load, but it will also not fire an onerror event, because the block happens before the browser processes the response. Timing-based checks see a request that resolved instantly with no payload, which is difficult to distinguish from a fast server. Many legacy detectors classify this as 'no blocker present' when the reality is 'MV3 blocker active'.

The signals that do survive MV3 are subtler. A natively blocked request has a timing fingerprint that differs from a real network error. A request redirected to a noop extension resource returns an identifiable empty payload rather than an actual error. These signals are real and readable, but they are invisible to a simple bait-element check and require dedicated timing and redirect-fingerprint probes to catch.

Scriptlet injection: active countermeasures inside the page

Some blockers go further than just blocking or hiding, they inject scriptlets that run inside the page and actively neutralise detection vectors. uBlock Origin and AdGuard both support scriptlet injection under Manifest V2. Scriptlets can override window.performance.now to reduce timing resolution, intercept and suppress XMLHttpRequest error callbacks, or normalise the offsetHeight of hidden elements to non-zero, so bait-element checks return false negatives even though the blocker is active.

These countermeasures are targeted at known techniques. When a detection method becomes popular enough to be noticed by a filter-list maintainer, a scriptlet gets written against it. The maintainer publishes the scriptlet; every user with that list gets it on the next sync; the detection vector goes dark across that entire userbase simultaneously. This is the adversarial loop that makes any single technique a short-lived advantage.

The implication is that a detector with only a few vectors is only one scriptlet rule away from being fully neutralised. An ensemble that votes across many independent vectors, each using a different mechanism, forces a countermeasure author to write and maintain a separate scriptlet for every one. That is a much higher cost than targeting a single-vector detector, and it buys detection considerably more staying power.

What evasion-resistant detection requires

Evasion-resistant detection needs three structural properties. First, a moving surface: bait elements, request paths and variable names that change on every page load, so no fixed pattern can be listed. A name that is different for every visitor has no canonical form to target with a filter rule.

Second, an ensemble of independent vectors. The vectors should use genuinely different mechanisms, DOM observation, network timing, noop-redirect fingerprinting, self-hosted asset checks, browser API probes, so they are not all susceptible to the same countermeasure. When one vector goes dark, the others continue voting and the ensemble still reaches a reliable verdict.

Third, nightly retraining. Filter lists, blocker versions and scriptlet libraries change daily. A detection engine that does not update against those changes becomes stale within weeks. AntiAdBlock Core retrains its heuristics every night against EasyList, uBlock and AdGuard deltas, so when a new countermeasure appears the probes adapt before the detection rate falls. That loop, observe, adapt, redeploy, is what separates a maintained engine from a static snippet that used to work.

The chrome-mv3-ad-blocking-publishers guide explains how Manifest V3 changed the evasion landscape for Chrome users, and why static bait scripts became the easiest thing to neutralise under declarativeNetRequest. For what detection looks like when all of these evasion scenarios are covered, anti-adblock that actually works walks through the validation process.

Frequently asked questions

Can an ad blocker block my anti-adblock detection script?

Yes. Filter lists include rules that block known detection scripts by URL, and blockers like uBlock Origin can also inject scriptlets that neutralise specific detection vectors inside the page. A detection script served from a fixed, publicly known URL with predictable bait patterns is the easiest target.

Why does bypass adblock detection cause silent failures rather than visible errors?

Most evasion makes the detection script conclude that no blocker is present, a false negative rather than a crash. The script still loads and runs, but the signals it looks for are absent or manipulated. From your dashboard it appears as low ad-block usage; in reality the detector is being defeated quietly.

What is the most evasion-resistant form of adblock detection?

An ensemble of many independent detection vectors, served from a randomised, signed, origin-locked path, retrained nightly against filter-list changes. No single countermeasure can defeat all vectors simultaneously, and the moving delivery surface prevents filter-listing. AntiAdBlock Core uses 11 voting vectors updated every night for exactly this reason.

Put the best adblock killer script to the test.

Free up to 10,000 detections per month. 60-second install.

Keep reading

Explore more