AdBlock & DNS-Blocker detection for websites/web apps.
Most users dont hide ads anymore, but block ad domains at network or DNS level (DNS, Pi-hole, VPNs). This finds DNS/network blocking and visual blockers. Protect ad revenue and analytics.
- Network Test: Sends requests to ad-networks. If enough fail, an ad blocker is detected. This catches DNS blockers, Pi-hole, and VPNs, AD-Blockers.
- Banner Scan: Injects hidden elements with ad-like names and watches them with MutationObserver.
I recommend using AD-domains which are used by your own ad/analytics functions, by specifying them in the configuration. (testUrls as string[])
npm install ad-blockguardCDN
<script src="https://cdn.jsdelivr.net/npm/ad-blockguard/dist/blockguard.min.js" crossorigin="anonymous"></script>With integrity:
<script
src="https://cdn.jsdelivr.net/npm/ad-blockguard/dist/blockguard.min.js"
integrity="sha256-replace.with.hash"
crossorigin="anonymous">
</script>Generate hash:
openssl dgst -sha256 -binary blockguard.min.js | openssl base64 -A
<script src="https://cdn.jsdelivr.net/npm/ad-blockguard/dist/blockguard.min.js"></script>
<script>
var BGClass = window.BlockGuard.default || window.BlockGuard;
new BGClass({
debug: true,
testUrls: ["https://adsense232.com/adsense-script.js", "https://cdn87.analytics.com/script.js", "https://matomoserver.host/watch"],
bannerScan: true,
customBaitClasses: ["banner-names", "similar to", "my served-ones", "pub-738360"]
onDetected: function () {
//you could even bind this to window.gtag being not available
document.getElementById('adblock-warning').style.display = 'block';
},
onNotDetected: function () {
alert("Thanks for not using an ADBlocker, you get 0.0̅01 BTC for this. 🙂")
}
});
</script>
<div id="adblock-warning" style="display:none">
Please disable your ad blocker to support this site.
</div>Install and create a client component:
// components/AdBlockGuard.jsx
'use client';
import { useBlockGuard } from 'ad-blockguard/react';
export default function AdBlockGuard() {
const { detected, checking } = useBlockGuard({
networkThreshold: 2,
gtag: true,
});
if (checking) return null;
if (!detected) return null;
return (
<div className="adblock-overlay">
<p>Please disable ad blocker to continue. 🙏</p>
<button onClick={() => window.location.reload()}>disabled it</button>
</div>
);
}Add it to your main layout to run on all pages:
// app/layout.jsx
import AdBlockGuard from '@/components/AdBlockGuard';
export default function RootLayout({ children }) {
return (
<html>
<body>
<AdBlockGuard />
{children}
</body>
</html>
);
}<!-- components/AdBlockGuard.vue -->
<script setup>
import { useBlockGuard } from 'ad-blockguard/vue';
const { detected, checking } = useBlockGuard({
networkThreshold: 2,
gtag: true,
});
</script>
<template>
<Teleport to="body">
<div v-if="!checking && detected" class="adblock-overlay">
<p>Please disable your ad blocker to support this site.</p>
<button @click="$router.go(0)">I've disabled it</button>
</div>
</Teleport>
</template>Nuxt SSR note: The composable auto-detects server-side rendering and skips all DOM operations safely.
make component to use later in root layout file:
***
// src/components/AdBlockGuard.astro
***
<div id="bg-warning" style="display:none">
Please disable your ad blocker.
</div>
<script>
import BlockGuard from 'ad-blockguard';
new BlockGuard({
onDetected: () => {
document.getElementById('bg-warning').style.display = 'block';
}
});
</script>Then import the component into your main layout and use it:
***
// src/layouts/Layout.astro
***
---
import AdBlockGuard from '../components/AdBlockGuard.astro';
---
<!doctype html>
<html lang="en">
<head>
// here were some meta tags
<title>Astro</title>
</head>
<body>
<AdBlockGuard />
<slot />
</body>
</html>A WordPress plugin is available as .zip file, see /integrations/wordpress. (you'll also find a tutorial on how to use it there)
All options are optional, but configuration is recommended. Pass them to new BlockGuard({ ... }) or useBlockGuard({ ... }). (new ... is for pure JS/Astro. the second one is for hooks(react/nuxt/vue/vite/next.js))
| Option | Type | Default | Description |
|---|---|---|---|
checkOnLoad |
boolean |
true |
Auto-run detection when the page loads. Automatically set to false in React/Vue hooks. |
networkTest |
boolean |
true |
Detect DNS/network-level blockers (AdGuard DNS, Pi-hole, VPNs) via HEAD requests. |
bannerScan |
boolean |
false |
Detect visual ad blockers (e.g. uBlock Origin) by injecting hidden bait elements. |
debug |
boolean |
false |
Print detailed logs to the browser console. Useful during development. |
| Option | Type | Default | Description |
|---|---|---|---|
testUrls |
string[] |
(built-in list) | Replaces the default URL list. Use your own ad/analytics URLs for best accuracy. |
extraTestUrls |
string[] |
[] |
Adds URLs to the default list without replacing it. |
networkTestCount |
number |
3 |
How many URLs to randomly pick and test per check. |
networkThreshold |
number |
2 |
Minimum number of blocked URLs required to trigger detection. |
networkTimeout |
number |
5000 |
Milliseconds before a request is considered blocked (timeout). |
| Option | Type | Default | Description |
|---|---|---|---|
customBaitClasses |
string[] |
[] |
Additional CSS classes for bait ads, e.g. form ads you serve. |
baitCheckInterval |
number |
100 |
Interval in ms between each bait visibility check. |
baitCheckAttempts |
number |
5 |
Max checks before the banner scan stops (def.interval(100ms) * def.attempts(5)= 500ms). |
| Option | Type | Default | Description |
|---|---|---|---|
gtag |
boolean |
false |
If true and window.gtag is present, fires a GA4 event automatically on detection. |
gtagEventName |
string |
"adblock_detected" |
The GA4 event name (for dashboard). |
gtagParams |
object |
{} |
Extra parameters sent with the event, like { page_type: 'article' }. |
analyticsCallback |
function |
null |
Custom callback for any analytics provider (Plausible, Matomo, etc.). Receives (detected, reason, details). |
| Option | Type | Description |
|---|---|---|
onDetected |
function |
called when a blocker is detected (no parameters) |
onNotDetected |
function |
called when all tests pass (no blocker;no parameters) |
onResult |
function |
always called after detection. Receives (detected: boolean, reason: string, details: object). |
const guard = new BlockGuard(options);
guard.check(); // Manually trigger a detection run. Returns Promise<boolean | null>
guard.reset(); // Clear results and allow re-running check(). Returns `this`.
guard.destroy(); // Remove all DOM elements and listeners. Use in React useEffect cleanup.
guard.onDetected(fn); // Add a detected callback. Returns `this` (chainable).
guard.onNotDetected(fn);// Add a not-detected callback. Returns `this` (chainable).
guard.getResult(); // Returns: true | false | null (null = not checked yet)
guard.getReason(); // Returns a detection reason string, like 'network_blocked'
guard.getDetails(); // Returns the full result object including per-URL network results| Reason | Trigger |
|---|---|
network_blocked |
≥ threshold URLs failed the network test |
bait_blocked |
an ad was hidden by CSS |
bait_removed |
an ad was removed |
bait_modified |
an ad's class/style was modified |
all_passed |
no blocking detec. |
If GA4 is initialized on your page (via Google Tag Manager or gtag.js snippet), setting gtag: true is enough, BlockGuard will call window.gtag('event', ...) automatically.
new BlockGuard({
gtag: true,
gtagEventName: 'adblock_detected', // default
gtagParams: { page_type: 'premium_article' } // optional extra params
});For other analytics providers (Plausible, Matomo, Fathom):
new BlockGuard({
analyticsCallback: function(detected, reason) {
if (detected) {
plausible('Adblock Detected', { props: { reason: reason } });
}
}
});(please check if this is correct for your provider, but i think all of them have similar approaches)
mini projects and short guides are available in /integrations:
/integrations/vanilla-js— Plain HTML + CDN/integrations/nextjs-react— Next.js App Router/integrations/nuxt-vue— Nuxt/integrations/astro— Astro/integrations/wordpress— WordPress Plugin (the .zip file; with tutorial)
Full TypeScript support is included. No @types/ package needed.
import BlockGuard, { BlockGuardOptions } from 'ad-blockguard';
const options: BlockGuardOptions = {
networkThreshold: 2,
onDetected: () => console.log('Blocked!'),
};
const guard = new BlockGuard(options);The idea of BlockGuard was partly inspired from BlockAdBlock by sitexw, thanks ^^
Pull requests are welcome! Please open an issue first to discuss what you would like to change, thanks. 😉🤝
MIT © 2026 Ponk445