Dealing with the "Invisible" User: Modern Ad-Block Detection in 2026




 If you are still using a script named ads.js to detect ad blockers, you are living in 2014. Modern blockers like uBlock Origin, AdGuard, and Brave Shields have become incredibly "smart." They don't just block scripts; they perform Cosmetic Filtering—letting your scripts load but hiding the elements from the UI so your detection logic never triggers.

In this post, we’ll explore the industry-standard ways to detect blockers in vanilla JS and modern frameworks like React, Angular, and Vue.

1. The Strategy: Why "Bait & Check" is King

The most reliable way to catch a blocker today is to "bait" it. We create a DOM element that looks exactly like an advertisement to a machine, then we check if the browser has forcibly hidden it.

The Vanilla JavaScript Implementation

We create a div with high-trigger class names (like .ad-placement) and check its offsetHeight.

JavaScript
function isAdBlockActive() {
  const bait = document.createElement('div');
  // Use classes found in common filter lists like EasyList
  bait.className = 'ad-placement adsbox banner-ad';
  bait.style.cssText = 'position:fixed; left:-999px; height:1px; width:1px;';
  
  document.body.appendChild(bait);

  return new Promise((resolve) => {
    // Give the blocker 100ms to "sniff" and hide the element
    setTimeout(() => {
      const isBlocked = window.getComputedStyle(bait).display === 'none' || 
                        bait.offsetHeight === 0;
      bait.remove();
      resolve(isBlocked);
    }, 100);
  });
}

// Usage
isAdBlockActive().then(active => {
  if(active) console.log("AdBlock is doing its job!");
});

2. Framework-Specific Implementations

In the world of SPAs (Single Page Applications), we need to handle component lifecycles so that detection runs only when the component is mounted.

React: The Custom Hook Pattern

Hooks are the cleanest way to share this logic across your dashboard or blog pages.

JavaScript
import { useState, useEffect } from 'react';

export function useAdBlockDetector() {
  const [isBlocked, setIsBlocked] = useState(false);

  useEffect(() => {
    const bait = document.createElement('div');
    bait.className = 'pub_300x250 ad-unit';
    bait.style.cssText = 'position:absolute; top:-1000px; width:1px; height:1px;';
    document.body.appendChild(bait);

    const timer = setTimeout(() => {
      if (window.getComputedStyle(bait).display === 'none' || bait.offsetHeight === 0) {
        setIsBlocked(true);
      }
      bait.remove();
    }, 200);

    return () => clearTimeout(timer);
  }, []);

  return isBlocked;
}

Angular: The Detection Service

For Angular devs, wrapping this in a @Injectable service ensures you can inject the status anywhere in your app.

TypeScript
@Injectable({ providedIn: 'root' })
export class AdDetectorService {
  public isBlocked = false;

  constructor() {
    this.checkStatus();
  }

  private checkStatus() {
    const bait = document.createElement('div');
    bait.className = 'ads-container google-ads';
    document.body.appendChild(bait);
    
    setTimeout(() => {
      this.isBlocked = window.getComputedStyle(bait).display === 'none';
      bait.remove();
    }, 200);
  }
}

3. Top Industry Libraries

If you don't want to maintain your own "bait list" of CSS classes, these libraries stay updated with the latest blocker bypasses:

  • Check-Adblock: A tiny, modern NPM package (<1KB). Perfect for React/Vite projects.

  • BlockAdBlock: The gold standard for Vanilla JS. It handles cross-browser edge cases (like Brave's aggressive shields) automatically.

  • Google Tag Manager (GTM): If your GTM script fails to fire a "heartbeat" event to your server, it’s a non-intrusive way to log blocking stats in your analytics.


4. The "DEAL" Approach: What to do next?

Detecting is only half the battle. The IAB (Interactive Advertising Bureau) recommends the DEAL framework:

  1. Detect: Use the code above.

  2. Explain: Tell the user that ads pay for the server costs.

  3. Ask: Request them to whitelist your site.

  4. Lift/Limit: Either show the content anyway (Lift) or restrict features (Limit).

Pro Tip: Don't be too aggressive. Users are generally okay with ads if they aren't intrusive. Instead of a hard "Blocker Block," try a friendly "Support our Writers" banner.


Conclusion

Ad blockers are part of the modern web ecosystem. By using Mutation Observers or Bait Elements, you can accurately measure your "shadow audience" and make data-driven decisions about your monetisation strategy.

Post a Comment

Previous Post Next Post