AntiAdBlock.Core

Implementation

11 min readBy The AntiAdBlock Core Team

Detection API: run your own logic on every adblock detection

Available on Max and Business, the Detection API turns our script into a headless detector: the same engine, no overlay, and a JavaScript event your code consumes to redirect, gate or measure however you want. This is the complete integration reference, from the tag to the payload.

What the Detection API is

Every site in AntiAdBlock Core runs in one of two script modes. Recovery is the default: the script detects the ad blocker and shows our recovery overlay, which walks the visitor through disabling it. Detection API is the headless alternative: the exact same detection engine runs on every page view, but nothing is ever rendered. Instead, the script delivers the result to your own JavaScript.

Pick the Detection API when you already have your own reaction in mind: redirecting visitors with a blocker to a specific page, showing your own wall or message, feeding the result into your analytics, or passing it to your backend so your server decides what to serve. If what you want is to convert blocked visits back into ad revenue with no work on your side, stay on Recovery; the recovery vs detection comparison covers that decision in depth.

The mode is chosen per site, so one account can run the overlay on one domain and the API on another. It is available on the Max and Business plans, and detections, stats and quota behave exactly the same in both modes.

Step 1: install the script tag

The integration has two parts, and this one is required: our script tag is the piece that runs the detection. Your code never detects anything itself; it only consumes the result. So the tag must stay installed exactly as your dashboard generates it, on every page where you want an answer.

You will find your tag in the dashboard under your site's Overview tab, in the card named Your script tag, with a copy button. It looks like this, with your real site id in both places:

<script async
  src="https://antiadblockcore.com/s/YOUR_SITE_ID.js"
  data-aabc-site="YOUR_SITE_ID"
  crossorigin="anonymous"></script>

Paste it inside the <head> of your pages, as early as you can. It loads with async, so it never blocks your rendering or your own scripts. It is also domain-locked: it only executes on the verified host it belongs to, so a copy of your tag pasted on another domain does nothing.

If your site sends a Content-Security-Policy, allow the https://antiadblockcore.com origin in script-src and connect-src, and ideally in img-src and style-src too. The detector loads a handful of bait resources to probe the blocker, and a policy that blocks those probes can degrade the signal.

Step 2: switch the site to Detection API mode

Open your dashboard, enter the site, and go to the Configuration tab. The first card is Script mode, with two options: Recovery and Detection API. Pick Detection API and confirm. That is the whole activation: no code change, no new tag, no redeploy.

The change applies to new page loads within seconds. From that moment the recovery overlay stops rendering on that site and the script starts emitting the aabc:detection event instead. The same card shows a Last event chip, which tells you when the script last reported from your site; it is the quickest way to confirm the wiring end to end.

If the option shows a lock, your current plan does not include the capability; it unlocks on Max and above. And if you ever downgrade below that, the site automatically falls back to the Recovery overlay so it never goes unprotected; your mode preference is kept and restored when the capability returns.

Step 3: receive the result in your code

The script hands you the result through three surfaces. They all carry the same payload, so you can use whichever fits your architecture, or several at once.

First, a CustomEvent named aabc:detection, dispatched on window (not on document). This is the natural fit when your code uses standard event wiring:

<script>
  window.addEventListener("aabc:detection", function (event) {
    var d = event.detail; // { detected, blockerType, path, browser }
    if (d.detected) {
      // Your logic here
    }
  });
</script>

Second, a plain callback: if window.AABC_ON_DETECT is a function at the moment of emission, the script calls it directly with the same detail object. Define it before our tag so it exists when the result arrives:

<script>
  window.AABC_ON_DETECT = function (d) {
    if (d.detected) {
      // Your logic here
    }
  };
</script>

Third, a snapshot: window.AABC_DETECTION always holds the latest detail object. Code that runs after the event has already fired, a late-loaded module for example, can just read it instead of having missed the moment.

Ordering matters for the first two: register your listener or define your callback before our script tag in the HTML. If you cannot control the order, rely on the snapshot as the fallback, as the pattern further down does.

Payload reference

Every emission carries a frozen detail object with four fields:

{
  "detected": true,
  "blockerType": "extension",
  "path": "A",
  "browser": "chromium"
}

detected is a boolean, and false is delivered explicitly: when the script finishes its pass and finds no blocker, you still get the event with detected set to false. You always get an answer when the script runs; you never have to infer a negative from silence.

blockerType classifies what is doing the blocking, and is null when detected is false. Possible values: extension (an installed blocker such as uBlock Origin or AdBlock Plus), brave_shields (the Brave browser's built-in blocking), network_dns (blocking that happens outside the browser, at the DNS or network level: AdGuard DNS, Pi-hole, some carriers), browser_protection (a browser's own protection mode, such as strict tracking protection), and unknown when the engine detects blocking but cannot attribute it. The network_dns group matters commercially: those visitors usually cannot switch their blocking off with one click, so treat them differently in your own flow if you show instructions.

browser is a coarse family tag for convenience: chromium, firefox, edge, brave, webkit or other. It saves you a user-agent parse for simple branching, and it is what lets you pair blockerType with the right instructions.

path is an internal detection path identifier. You do not need to branch on it; include it if you log results; it speeds up support diagnosis.

Event timing and single-page apps

The engine runs once per full page load and usually resolves shortly after the page settles. You should design for one decision per document.

On a single page it can emit more than once: detection runs in passes, and if a later pass changes the result (detected flips, or blockerType is refined from unknown to something specific) the event fires again with the updated detail. The snapshot always holds the latest version. The practical pattern: act on the first event, and only re-read the snapshot later if the classification matters to you.

In single-page applications the event does not re-fire on client-side route changes; there is no re-check per virtual navigation. Take the result once per real page load and keep it for the session, or force a full reload where you need a fresh answer.

Handling a missing result

There are situations where the script emits nothing at all: the visitor's blocker prevented our script from loading in the first place, the traffic is a crawler or automation (detection is deliberately silent for bots, so your SEO is never affected by it), the site is not verified yet, or the monthly quota ran out. Silence therefore means "no answer", never "no ad blocker".

Because of that, any flow that waits for the result needs a bounded wait with a default decision. This is the reference pattern; it checks the snapshot first so it also works when your code runs late:

<script>
  (function () {
    var decided = false;
    function decide(d) {
      if (decided) return;
      decided = true;
      // d === null  -> no answer in time: apply your default route
      // d.detected  -> your decision, with d.blockerType / d.browser
    }
    if (window.AABC_DETECTION) return decide(window.AABC_DETECTION);
    window.addEventListener("aabc:detection", function (e) { decide(e.detail); });
    setTimeout(function () { decide(null); }, 3000);
  })();
</script>

Choose the timeout that fits your flow; around three seconds covers slow connections. With this pattern in place, a page view that gets no answer simply takes your default route, and your page never waits beyond the limit you set.

Full integration example

The following minimal head redirects blocked visitors to a notice page. The handler is defined first, then our tag; the site id comes from your dashboard:

<head>
  <!-- 1. Your handler, defined BEFORE our tag -->
  <script>
    window.AABC_ON_DETECT = function (d) {
      if (d.detected) {
        window.location.replace("/adblock-notice");
      }
    };
  </script>

  <!-- 2. The AntiAdBlock Core tag, exactly as your dashboard generates it -->
  <script async
    src="https://antiadblockcore.com/s/YOUR_SITE_ID.js"
    data-aabc-site="YOUR_SITE_ID"
    crossorigin="anonymous"></script>
</head>

Swap the redirect for whatever your product needs: set a flag your app reads, show your own modal, or send the result to your backend with fetch and let the server decide on the next request. The contract is always the same: our tag detects, your code reacts.

Security considerations

A CustomEvent travels through the page like any other event, which means other scripts running on your page, including blocker scriptlets, can theoretically intercept it, stop it or even dispatch a fake one. For casual use that risk is small, but if your flow makes a decision you care about, prefer window.AABC_ON_DETECT: our script invokes your function directly, so there is nothing in between to swallow or forge the call.

Either way, treat the client-side signal as a convenience, not a security boundary. Anything a browser runs can be tampered with by the person holding the browser. Enforcement that must hold, paid content gates for example, belongs on your server; and the canonical detection numbers are the ones in your dashboard, computed from server-side ingestion, not whatever an individual client claims.

Effect on stats, quota and site settings

Billing does not change: your quota counts adblock detections, one per page view identified as blocked, and plain page views without a blocker never consume anything. A site in Detection API mode consumes exactly what it would in Recovery mode.

Your dashboard keeps working too. Detections, blocker type breakdowns and the daily activity chart fill in as always. The Recovery KPI keeps reporting, with one change of meaning: since our overlay never shows, recoveries now measure the outcome of your own flow, visitors who came back with the blocker off after whatever you showed them.

Overlay customization and the network-blocked visitor settings are saved but inert while the site is in this mode, since there is no overlay to apply them to. Switch the site back to Recovery and they apply again exactly as stored.

Testing and troubleshooting

To verify the integration: install a blocker such as uBlock Origin in your own browser, open your site, and type window.AABC_DETECTION in the DevTools console. You should see the detail object with detected set to true. Then disable the blocker, reload, and check you get detected false. The Last event chip in the Script mode card confirms the server saw your script report.

If nothing fires, check the following in order: the site is verified and active in your dashboard; the tag is present in the served HTML (view source, do not trust the framework template); the site is saved in Detection API mode; your plan includes the capability; your listener or callback is registered before our tag, or you are reading the snapshot; you are not testing through headless automation, which is intentionally ignored; and your Content-Security-Policy, if you have one, allows our origin. If you get events but detection seems off for a specific setup, note the path field and read how detection works under the hood before writing in, and include both in the ticket.

Frequently asked questions

Does the event fire when no ad blocker is found?

Yes. When the engine finishes and finds nothing, the event still fires with detected set to false and blockerType null. You always get an explicit answer when the script runs; silence only happens when the script could not run or was deliberately quiet, which is why your code should treat silence as "no answer".

Do detections in this mode count against my quota?

Yes, identically to Recovery mode: one detection per page view identified as using an ad blocker. Page views without a blocker never count in either mode.

Can I run the overlay on one site and the Detection API on another?

Yes. The mode is a per-site setting, so each site in your account chooses independently in its Configuration tab.

What happens if I downgrade below Max?

The site automatically returns to Recovery mode and the overlay shows again, so it never goes unprotected. Your Detection API preference is stored and restored if the capability comes back.

Does it work in single-page applications?

Once per full page load. The event does not re-fire on client-side route changes, so take the result when the document loads and keep it, or force a real reload where you need a fresh check.

Can I rely on the event to protect paid content?

No. It is a client-side signal and anything client-side can be tampered with by the visitor. Use it for UX decisions and measurement, prefer AABC_ON_DETECT for robustness, and keep real enforcement on your server.

Put the best adblock killer script to the test.

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

Keep reading

Explore more