API reference // reviewed

Adblock detection API reference

This reference documents the public contract of the AntiAdBlock Core Detection API: the aabc:detection window event, the window.AABC_ON_DETECT callback, the window.AABC_DETECTION snapshot, the four result fields and their values, when the result fires and what silence means. Detection is the same as in Recovery mode, but nothing is shown on screen; your code decides the rest.

The Detection API comes with Max ($12.99 a month) and Business. Free runs the same engine with the notice: 5,000 detections a month, no payment method.

The contract at a glance

event
aabc:detection, on window
callback
window.AABC_ON_DETECT(result)
snapshot
window.AABC_DETECTION
result
{ detected, blockerType, path, browser }
fires
once per page, also when detected is false; again only if the result changes on a tab revisit
silence
no result means no answer: fail open
Minimal example: your code, then the tag
<script>
window.AABC_ON_DETECT = function (result) {
  // Your logic here.
};
</script>
<script async
  src="https://antiadblockcore.com/s/SITE_ID.js"
  data-aabc-site="SITE_ID"
  crossorigin="anonymous"></script>

Enable it

The Detection API is a per-site setting on the Max and Business plans. Every site starts in Recovery mode, the default, which shows our notice. To switch, open the site in your dashboard, go to the Configuration tab and choose Detection API in the Script mode card; the card is available once the domain is verified.

No new tag is needed. Pages opened after the change get the new mode within a minute, while a page that is already open keeps the mode it loaded with. In this mode the notice isn't even part of the script your visitors download. Resetting the site's notice customization to the defaults also switches it back to Recovery mode, and the result stops being sent.

Requires The AntiAdBlock Core script tag on a site in Detection API mode (Max or Business plan).

The Detection API comes with Max ($12.99 a month) and Business. Free runs the same engine with the notice: 5,000 detections a month, no payment method.

The script tag

The same tag runs both modes. Copy it from the Your script tag card in the site's Overview tab and paste it into the <head> of every page where you want a result, as early as you can. It loads with async, so it never blocks rendering.

Example tag, standard delivery
<script async
  src="https://antiadblockcore.com/s/SITE_ID.js"
  data-aabc-site="SITE_ID"
  crossorigin="anonymous"></script>

This example uses SITE_ID. A new site gets first-party delivery by default: once its DNS record is live, your dashboard shows a tag whose src is on a subdomain of your own domain, for maximum detection. Use the tag exactly as the dashboard gives it, without wrapping it in another loader. For each platform, see where the tag goes on WordPress, Shopify, Next.js and more.

The script is tamper-protected and bound to your domain: it runs on your verified domain and its subdomains, and stays silent anywhere else.

The result payload

Every result is a frozen, read-only object with exactly four keys. The same object reaches the event, the callback and the snapshot, and it uses the same blocker types as your dashboard.

Fields of the Detection API result
FieldTypeValuesMeaning
detected booleantrue, falseWhether an ad blocker was confirmed on this page.
blockerType string or nullextension, brave_shields, browser_protection, network_dns, unknown, nullWhat is doing the blocking. null when detected is false.
path string or nullan internal reference letter, FORCE, or nullReference code for support tickets; it doesn't change what you should do. FORCE marks the manual test. null when detected is false.
browser stringchromium, firefox, edge, brave, webkit, otherThe visitor's browser family. Always set.
Blocker found
{
  "detected": true,
  "blockerType": "extension",
  "path": "…",
  "browser": "chromium"
}
No blocker
{
  "detected": false,
  "blockerType": null,
  "path": null,
  "browser": "firefox"
}

In the first example, path is elided: it holds an internal reference letter.

blockerType values

extension
an ad-blocking browser extension.
brave_shields
the Shields built into the Brave browser.
browser_protection
the browser's own protection, such as a strict tracking protection mode. On Firefox and Edge, network-only blocking is reported here too, the same way your dashboard reports it.
network_dns
blocking outside the browser, at network or DNS level, such as Pi-hole, AdGuard DNS or NextDNS. These visitors usually can't turn it off in one click, so treat them differently: asking them to allow your site only frustrates them.
unknown
a blocker was confirmed but not attributed to one of the types above.

TypeScript

Types for the contract (aabc-types.ts)
export type AabcResult = Readonly<{
  detected: boolean;
  blockerType:
    | "extension"
    | "brave_shields"
    | "browser_protection"
    | "network_dns"
    | "unknown"
    | null;
  // a reference code; "FORCE" for the #aabc_force test
  path: string | null;
  browser:
    | "chromium"
    | "firefox"
    | "edge"
    | "brave"
    | "webkit"
    | "other";
}>;

declare global {
  interface Window {
    AABC_DETECTION?: AabcResult;
    AABC_ON_DETECT?: (result: AabcResult) => void;
  }
  interface WindowEventMap {
    "aabc:detection": CustomEvent<AabcResult>;
  }
}

The payload carries these four keys and nothing else. Because it is frozen, copy it (for example with { ...result }) before you add fields of your own.

Three ways to read the result

Use whichever fits your setup, or several: all three carry the same object. For each result, the snapshot is updated first, then the event fires, then the callback is called. When the decision matters, use the callback: the script calls your function directly.

  1. snapshot
  2. event
  3. callback

Window event: aabc:detection

A CustomEvent dispatched on window, not on document, with the result in event.detail. Add the listener before our script tag so it is ready when the result fires.

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

Callback: window.AABC_ON_DETECT

Define this global and the script calls it with the same object. It is looked up each time a result is sent, so it has to exist by then; defining it before our tag is the simple way to be sure. An error thrown inside your function doesn't stop our script; it is caught silently, so wrap your logic in your own try/catch if you want to log it.

window.AABC_ON_DETECT
<script>
window.AABC_ON_DETECT = function (result) {
  if (result.detected &&
      result.blockerType !== "network_dns") {
    // Your logic here.
  }
};
</script>

Snapshot: window.AABC_DETECTION

The latest result, kept on window for code that runs late, which is common in single-page apps. It is undefined until the first result and always holds the same object the event and the callback received.

window.AABC_DETECTION
var result = window.AABC_DETECTION;
if (result && result.detected) {
  // Your logic here.
}

When it fires

  • Once per page, after the first full evaluation: roughly 0.1 to 3.6 seconds in, and never before DOMContentLoaded. Anything you register before DOMContentLoaded is in time; code that loads later should read the snapshot.
  • It fires when detected is false too, so a page without a blocker gets an explicit answer, not silence.
  • When the visitor comes back to the tab, the script checks again and sends a new result only if detected or blockerType changed. A change to false lets you remove a message you already showed. A re-check never counts as a second detection.
  • A client-side route change doesn't produce a new result (see single-page apps).
One page, from open to result
  1. page opens
  2. DOMContentLoaded
  3. result, about 0.1 to 3.6 s
  4. tab revisited
  5. new result only if it changed

When no result arrives

Silence is not "no ad blocker". No event, callback or snapshot is produced when:

  • the site is in Recovery mode (the default, and where it returns after a plan change or a reset of the notice customization): the result is only sent in Detection API mode;
  • our tag isn't on the page, or didn't load there;
  • the domain isn't verified yet;
  • the site or its script is paused or switched off, or the account isn't active;
  • the account's monthly detection quota is used up (we email you at 80%, and results come back with the next cycle);
  • the tag runs on a domain it isn't bound to;
  • the visitor is identified as a bot or an automated browser, including headless and WebDriver-driven test runs;
  • our service-wide kill switch is on.

The silent script carries no reason, by design. To see why a site is quiet, check its status in your dashboard and the Last event line in its Script mode card.

Treat a missing result as "no answer" and keep your normal path: in other words, fail open. If a flow waits for the result, give it a time limit and a default; the integration guide has a ready pattern.

Fail open
  • detected: true your response
  • false, or no result your normal path

Testing

Add #aabc_force to any URL on your own site and load or reload the page to force a positive result: detected: true and path: "FORCE", with nothing shown. It lets you run your handler without installing an ad blocker. blockerType and browser still describe the real visit, so without a blocker blockerType normally comes back as unknown. In Recovery mode, the same hash shows the notice instead.

If your handler runs, the integration works. In Detection API mode, the Script mode card also shows a Last event line with when your site last reported (it updates about once a minute; reload the Configuration tab to see it). Test in a regular browser window, the way a visitor opens your page. Automated browsers get no result: in end-to-end tests, call your own handler with a contract object instead.

Single-page apps and frameworks

The result fires when a page is opened or reloaded, and again on a tab revisit only if it changed. A client-side route change doesn't produce a new result. In a single-page app, register your listener once on window and read window.AABC_DETECTION after navigation for the last known result; for a fresh check, load the page again.

In React or Next.js, add the tag once (in Next.js, inside the <head> of the root layout, exactly as the dashboard gives it) and read the result with a small hook:

A small React hook (use-adblock-result.ts)
"use client";
import { useEffect, useState } from "react";
import type { AabcResult } from "./aabc-types";

export function useAdblockResult() {
  const [result, setResult] =
    useState<AabcResult | null>(null);
  useEffect(() => {
    const handle = (event: CustomEvent<AabcResult>) =>
      setResult(event.detail);
    window.addEventListener("aabc:detection", handle);
    if (window.AABC_DETECTION) {
      setResult(window.AABC_DETECTION);
    }
    return () =>
      window.removeEventListener("aabc:detection", handle);
  }, []);
  // null until a result arrives; stays null if none does
  return result;
}
Reading it in a client component
"use client";
import { useAdblockResult } from "./use-adblock-result";

// in a client component
export function Download() {
  const result = useAdblockResult();
  if (result && result.detected) {
    return <YourMessage blockerType={result.blockerType} />;
  }
  // the default path, also while there is no result
  return <DownloadLink />;
}

The hook reads the snapshot, so it also catches a result that arrived before your component mounted, and it removes its listener on unmount. The same two steps, listen for the event and read the snapshot, work in Vue, Svelte or plain JavaScript.

Analytics

To see your ad-block rate in your own analytics, forward one result per page. With Google Tag Manager, push it to the data layer and send it with a GA4 event tag on a Custom Event trigger named aabc_detection, reading the fields with three Data Layer Variables:

To the Google Tag Manager data layer
<script>
(function () {
  function send(result) {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: "aabc_detection",
      aabc_detected: result.detected,
      aabc_blocker_type: result.blockerType || "none",
      aabc_browser: result.browser
    });
  }
  if (window.AABC_DETECTION) {
    send(window.AABC_DETECTION);
  } else {
    window.addEventListener(
      "aabc:detection",
      function (event) { send(event.detail); },
      { once: true }
    );
  }
})();
</script>

The snippet sends one result per page: the one already in the snapshot, or else the first to arrive, and the listener removes itself. Register aabc_detected, aabc_blocker_type and aabc_browser as event-scoped custom dimensions in GA4 to report on them. Without Tag Manager, send the same fields with gtag("event", "aabc_detection", { ... }). Pages with no result send nothing. Many ad blockers also block Google Tag Manager and GA4, so part of the blocked visits never reach your analytics; your AntiAdBlock Core dashboard still counts every detection.

Quota and plan changes

  • A detection counts the same in both modes: one per page view where a blocker is found. Page views without one never count, and a re-check never counts twice.
  • The quota belongs to the account and is shared across its sites. We email you at 80%; when it is used up, the script stays silent until the next cycle (see when no result arrives).
  • Detections and blocker types keep flowing into your dashboard.
  • If a plan change removes the Detection API, the site goes back to Recovery mode on its own, so visitors with a blocker see our notice again. You get an email and a note in your dashboard; your choice is kept and returns when you upgrade.

Contract history

  1. Documentation reviewed: more cases with no result (Recovery mode, used-up quota, paused site, tag on another domain, automated browsers), the TypeScript types and the React and analytics examples are added, and path is documented as a reference code with no fixed list of letters. The contract doesn't change.

  2. First public version: the aabc:detection event, the AABC_ON_DETECT callback, the AABC_DETECTION snapshot and the four result fields.

Any change to the contract is listed here with its date.

Keep going

  • Detection API integration guide

    The step-by-step walkthrough: a full example with a time limit, missing results and troubleshooting.

  • Adblock detection API

    What you can build on the result, setup and plans.

  • Plans and pricing

    The Detection API comes with Max and Business; every plan and price is public.

  • Live demo

    A blocked visit, step by step, and an example site that runs the same engine with the notice.