AntiAdBlock.Core

Detection

9 min readBy the AntiAdBlock Core team

Detect AdBlock with JavaScript: Code Snippets and Why They Fall Short

A practical JavaScript adblock detection tutorial covering the bait-div method, fetch-based probes, and MV3 blind spots, plus when a managed solution makes more sense than rolling your own.

What Detecting AdBlock with JavaScript Actually Means

Ad blockers do not announce themselves. They operate silently at the browser level, intercepting network requests and hiding DOM elements before your page has a chance to render ad slots. Detecting them from JavaScript means your code has to infer their presence indirectly, by observing side effects they leave behind

The two most common side effects are: (1) a 'bait' DOM element that ad blockers hide because its class name matches a filter list entry, and (2) a 'bait' network request to a URL pattern that blockers intercept and block. Your JS checks whether the element is visible or whether the fetch succeeded, and draws a conclusion from there. Neither approach requires any browser permission, they work in plain vanilla JavaScript, no libraries needed

Publishers lose between 18% and 32% of ad impressions to blockers, depending on niche and audience. Even a basic detection layer lets you present a soft prompt or offer an ad-free subscription, but only if your detection is actually firing on the blockers your visitors use. That qualification matters more than it used to, as we will cover below

The classic bait-div method, and why it no longer holds up

The bait-div technique creates an invisible HTML element whose class names and dimensions mimic a real ad unit. uBlock Origin, AdBlock Plus, and similar list-based blockers apply cosmetic filters that set such elements to 'display: none' or 'visibility: hidden'. After a short delay, your script checks whether the element is still in the layout flow

We deliberately do not publish a runnable snippet here. The method itself is no secret: create an invisible element whose class name matches an ad-related entry on a public filter list such as EasyList, wait a moment, then check whether a blocker hid it. The problem is exactly that it is public and static. A fixed, well-known class name is the first thing a filter-list maintainer copies into a rule, and from then on the check quietly returns 'no blocker' for every visitor who carries that list.

The class names such snippets rely on, like the ones that appear in EasyList, the most widely used filter list, are public and fixed, so most list-based blockers on Manifest V2 will hide the element. That is also the whole weakness: a fixed, well-known signature is trivial to add to a filter rule, and once it is listed the check stops firing

This approach still catches AdBlock Plus and older uBlock Origin installs on Manifest V2. The catch, which we get to below, is that it is only a small part of the picture and it degrades the moment a filter list catches up, with no visible error to warn you

Fetch-based checks, and why Manifest V3 breaks them

Cosmetic-filter detection only catches blockers that hide elements. Some blockers, particularly Brave Shields and newer builds of uBlock Origin Lite (the Manifest V3 version), focus primarily on blocking network requests via 'declarativeNetRequest' rules rather than hiding DOM elements. For those, a fetch-based probe is more reliable

Again, we do not ship a runnable probe here. The idea is to request a path that looks ad-related and treat a failure as a blocker, which catches network-level blockers that a cosmetic check misses. In practice it is fragile: the probe path is another fixed, listable signature, a plain 404 or a corporate firewall looks identical to a real block and produces false positives, and under Manifest V3 the request is stopped in the browser engine before your code runs, so the signal is easy to misread.

The weakness is the same as with the bait element. The probe path is a fixed, listable signature, and a plain 404, a corporate firewall or certain VPNs can make the request fail with no blocker present, which produces false positives. Stacking two fragile static signals does not fix the underlying problem: both are public, both are easy to list, and both go quiet without warning

MV3 extensions like uBlock Origin Lite use 'declarativeNetRequest', which intercepts requests at the browser engine level before your JavaScript even runs. This means the fetch will fail silently, your 'catch' block fires, and the detection works. However, the rules engine in MV3 is more conservative than MV2's dynamic filtering, which can create edge cases where neither probe fires reliably. That is the core reason DIY detection degrades over time

Why DIY JavaScript Detection Degrades Silently

The fundamental problem with a hand-rolled adblock detector is maintenance entropy. Filter lists are updated daily, EasyList, EasyPrivacy, uAssets, and AdGuard's lists each push multiple updates per week. Every update is a potential change that breaks a bait element class name, adds a new URL pattern your probe does not cover, or introduces a cosmetic exception that lets your bait element survive even under a blocker. You will not notice when this happens unless you are actively testing against every major extension on every major browser on a weekly schedule

There are also structural blind spots. Brave Shields operates at the browser engine level, not as a JavaScript-accessible extension, so extension-detection APIs do not apply. DNS-level blockers like Pi-hole or NextDNS block requests before they reach the browser entirely, your fetch probe fires a request that never gets a response, but the failure signature looks identical to a transient network error. Without a timing fingerprint or a secondary out-of-band signal, you cannot distinguish the two. Our revenue calculator at /calculator can give you a sense of how many impressions you are likely missing across these categories

False positives are the other side of the coin. Aggressive privacy settings, corporate firewalls, and certain VPNs can cause a bait fetch to fail without any blocker being present. If you act on every detection signal by showing a hard paywall, you risk alienating a measurable fraction of non-blocking visitors. The precision of the detection layer, how many of its positive signals are true positives, matters as much as its recall

When to Use a Managed Anti-AdBlock Service

A DIY snippet is a reasonable starting point if you have a small site, a technically capable team, and the bandwidth to keep the detection logic current. For most publishers, those conditions do not hold simultaneously. The maintenance cost of staying current with filter list changes, browser engine updates, and MV3 rollouts is non-trivial, and the cost of getting it wrong is silent revenue leakage, the worst kind, because you do not know it is happening

AntiAdBlock Core runs a continuously maintained, multi-signal detection engine that updates against live filter lists. The precision is 99.7%, which means fewer false positives and fewer unnecessary friction events for your non-blocking visitors. The median whitelist rate across publishers on the platform is 65%, and the average revenue recovery is 38% of previously blocked impressions

The free tier covers 10,000 detections per month with no credit card required, enough to validate the detection signal on a real audience before committing to a paid plan. If you want to quantify what ad blockers are costing your specific site before signing up, the /calculator page runs the math against your traffic and CPM. Paid plans start at around $9 per month. Integration is a single '<script>' tag in your '<head>', no server-side changes, no webpack config, no dependencies

If you have reached the limits of handwritten detection code, detect adblock with JavaScript in 2026 covers the full picture of what has changed under MV3, including timing fingerprints and ensemble voting that no single-vector script can replicate. For context on what precision numbers from any detection service actually mean, anti-adblock detection accuracy explained gives you the benchmark questions.

Brave is the case a bait test alone will always miss, because the blocking is built into the browser: ad blocking on Brave covers what to look for.

Frequently asked questions

Does adblock detection JavaScript work against uBlock Origin Lite (MV3)?

Partially. uBlock Origin Lite uses `declarativeNetRequest` to block network requests at the browser engine level, so a fetch-based probe will still fail and return a blocked signal. However, MV3's cosmetic filtering is more limited, so bait-div checks are less reliable than against MV2 versions. A multi-vector approach, combining fetch probes, DOM checks, and timing fingerprints, is needed for consistent MV3 detection.

Can I detect Brave Shields with JavaScript?

Brave Shields operates at the browser engine level rather than as a traditional extension, so extension-specific APIs do not apply. Fetch-based probes that target known blocked URL patterns do work because Brave Shields intercepts those requests before they reach the network. A fetch to a path that looks ad-related will fail under Brave Shields' standard blocking mode, though on its own that signal is easy to misread.

How do I avoid false positives in adblock detection?

Use multiple independent signals and only act when at least two agree. A bait-div that is hidden AND a bait-fetch that fails is a much stronger signal than either alone. Also test against standard corporate proxies and VPN configurations, which can fail fetches without any blocker present. A 150–200 ms delay before inspecting bait elements reduces race-condition false positives.

Is it legal to detect ad blockers on my website?

In most jurisdictions, yes. Detecting an ad blocker involves observing the behavior of your own page in the visitor's browser, no personal data is collected by the detection mechanism itself. You are not bypassing any security measure. You should, however, ensure any subsequent action (paywall, consent prompt) complies with your jurisdiction's consumer protection and privacy laws.

Put the best adblock killer script to the test.

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

Keep reading

Explore more