How to Detect Ad Blockers in JavaScript
Detecting whether a user has an ad blocker enabled is a common requirement for websites that rely on ad revenue. While it's a constant cat-and-mouse game, there are several effective client-side techniques you can use to get a reasonably accurate detection.
This guide will teach you the modern and standard methods for detecting ad blockers. You will learn how to create a single, robust async function that combines two of the most reliable detection techniques: a "bait" network request and a "bait" DOM element.
The Core Concept: The "Bait and Switch"
Ad blockers work by maintaining a list of known ad-related URLs, filenames, and CSS selectors. They then block network requests to these URLs or hide DOM elements that match these selectors.
We can exploit this behavior to detect them. The logic is simple:
- Set the Bait: Try to create or request a resource that has a name commonly found on ad blocker filter lists (e.g.,
ads.js,google-ad-script). - Check the Trap: See if the resource was successfully loaded or created.
- Determine the Outcome: If the resource was blocked, it's highly likely an ad blocker is active.
The Modern Solution: A Reusable async Function (Best Practice)
The most robust approach is to combine two different detection methods into a single, easy-to-use function that returns a Promise. This makes the detection more reliable, as some ad blockers may block one type of bait but not another.
The Reusable Function:
/**
* Detects if an ad blocker is likely active.
* Combines two detection methods for better accuracy.
* @returns {Promise<boolean>} A promise that resolves to true if an ad blocker is detected.
*/
async function detectAdBlocker() {
// Method 1: Create a "bait" DOM element.
const baitElement = document.createElement('div');
baitElement.innerHTML = ' ';
baitElement.className = 'adsbox'; // A common class name targeted by ad blockers
baitElement.style.position = 'absolute';
baitElement.style.left = '-9999px';
document.body.appendChild(baitElement);
// Method 2: Make a "bait" network request.
const baitRequest = fetch(
'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
{ method: 'HEAD', mode: 'no-cors', cache: 'no-store' }
);
// Allow a moment for the browser and extensions to process
await new Promise(resolve => setTimeout(resolve, 100));
const isBaitElementBlocked = baitElement.offsetHeight === 0;
let isBaitRequestBlocked = false;
try {
await baitRequest;
} catch (error) {
// A failed network request is a strong indicator of an ad blocker
isBaitRequestBlocked = true;
}
// Clean up the bait element
document.body.removeChild(baitElement);
return isBaitElementBlocked || isBaitRequestBlocked;
}
How the Solution Works
Our function uses two independent checks:
-
DOM Element Check:
- We create a
divand give it the classadsbox, a name that is on many ad blocker filter lists. - Ad blockers will often apply a style like
display: none !important;to elements with this class. - We append this element to the DOM and then immediately check its
offsetHeight. If an ad blocker has hidden it, its height will be0.
- We create a
-
Network Request Check:
- We attempt to
fetcha well-known advertising script URL (in this case, Google'sadsbygoogle.js). - We don't need the response, so we use a lightweight
HEADrequest. - If an ad blocker is active, it will block this network request, causing the
fetchPromiseto reject. We catch this error and treat it as a positive detection.
- We attempt to
The function returns true if either of these checks indicates that an ad blocker is active.
Practical Example: Displaying a Message to the User
With our detectAdBlocker utility function, acting on the result becomes simple and readable.
<div id="adblock-message" style="display: none; color: red;">
It looks like you're using an ad blocker. Please consider disabling it to support our site.
</div>
Solution:
(async () => {
const isAdBlockerActive = await detectAdBlocker();
if (isAdBlockerActive) {
console.log('Ad blocker detected!');
document.getElementById('adblock-message').style.display = 'block';
} else {
console.log('No ad blocker detected.');
}
})();
Conclusion and Important Considerations
Detecting ad blockers is an inexact science, as it's a constant battle between publishers and ad-blocking technologies.
- The most reliable method is to use a multi-pronged "bait" approach, checking for both blocked DOM elements and blocked network requests.
- Encapsulating this logic in a single, reusable
asyncfunction is a best practice that makes your code clean and easy to use. - Be mindful of the user experience. Instead of blocking content entirely, it's often better to display a polite message asking the user to disable their ad blocker.
- No detection method is 100% foolproof, and the filter lists used by ad blockers are constantly changing.