How to detect adblock and show a respectful notice with JS in WordPress

Contents

Introduction

Detecting ad blockers and showing a respectful notice to users is a common need for WordPress publishers who rely on ad revenue. The goal: detect when an ad blocker is likely active and then show a lightweight, accessible, non-intrusive message explaining the impact of ad blocking and giving an easy option to dismiss the notice or whitelist the site. This article covers every practical detail: detection techniques (client and server), WordPress integration, enqueueing, accessible UI patterns, persistence (cookie/localStorage), internationalization, testing, and pitfalls to avoid.

Principles and best practices (summary)

  • Be respectful. Avoid blocking core content show a short polite message that explains why ads matter and how to whitelist.
  • Be lightweight and performant. Detection should not slow page rendering or introduce heavy network requests.
  • Prefer progressive enhancement. The site should work normally even if the notification logic fails.
  • Accessible and dismissible. Provide a clear way to dismiss the notice and ensure screen-reader access.
  • Minimize false positives. Use robust detection and allow users to dismiss if mistakenly flagged.
  • Respect privacy and legal obligations. Do not collect or send tracking data unnecessarily.

Overview of detection methods

No single technique is perfect because ad blockers evolve. Use a combination for higher reliability and a fallback server-side strategy if necessary. The main client-side methods:

  • Bait element: insert an element with a class or id commonly blocked (for example, ads, ad-banner) and check if it gets hidden or removed by CSS.
  • Blocked resource request: attempt to load a known ad-like URL (for example /ads.js or external ad-domain) and check for failure.
  • Script detection: detect if ad-related scripts were blocked (e.g., by injecting a script tag and verifying an expected global doesnt appear).
  • Injected variables: check for global signals some adblockers provide (rare and inconsistent).
  • Server-side heuristics: examine request headers, patterns, or use client-side result reporting when needed.

Bait element (recommended first approach)

A bait element is the simplest and least intrusive approach. Add a small element with class names that many adblockers target (for example: ad, ads, advert). The adblocker often hides it via CSS script then checks computed style or offsets.

Example JavaScript detection (place in an external file and enqueue in WordPress):

(function () {
  // Create a bait element
  var bait = document.createElement(div)
  bait.className = ad-banner ad adsbox advert ad-placeholder
  // Position off-screen and low-impact
  bait.style.position = absolute
  bait.style.left = -9999px
  bait.style.height = 10px
  bait.style.width = 10px
  document.body.appendChild(bait)

  // Give the browser a tick to calculate styles
  setTimeout(function () {
    var blocked = false
    try {
      // If display is none or offsetHeight is 0, likely blocked
      var style = window.getComputedStyle(bait)
      if (style  (style.display === none  parseInt(style.height) === 0  bait.offsetParent === null  bait.offsetHeight === 0)) {
        blocked = true
      }
    } catch (e) {
      // defensive fallback
      blocked = true
    }

    // Cleanup
    if (bait.parentNode) bait.parentNode.removeChild(bait)

    if (blocked) {
      // Trigger your notice function
      var event = new CustomEvent(adblockDetected)
      window.dispatchEvent(event)
    } else {
      var event = new CustomEvent(adblockNotDetected)
      window.dispatchEvent(event)
    }
  }, 50)
})()

Notes:

  • Keep the bait small and off-screen so it does not affect layout.
  • Use multiple class names to improve coverage.
  • Use a small timeout (50–200 ms) to allow CSS to apply avoid long delays.

Blocked resource request (more robust)

This approach tries to load a resource commonly blocked by adblockers. If the request fails or is blocked, that’s a signal. Use a same-origin path you control (e.g., /ads.js) or an intentionally named resource that will be blocked. Important: do not rely on loading external ad networks create a simple endpoint that returns a small JS file.

(function () {
  var url = /ads.js?v=1 // a short lightweight endpoint you create on your site
  var timedOut = false
  var timeout = setTimeout(function () {
    timedOut = true
    handleResult(false) // treat timeout as blocked/unreachable
  }, 1500)

  var s = document.createElement(script)
  s.src = url
  s.async = true
  s.onload = function () {
    if (!timedOut) {
      clearTimeout(timeout)
      // If script executed, adblock did NOT block this resource
      handleResult(true)
    }
  }
  s.onerror = function () {
    if (!timedOut) {
      clearTimeout(timeout)
      handleResult(false) // blocked or failed
    }
  }
  document.head.appendChild(s)

  function handleResult(notBlocked) {
    if (!notBlocked) {
      window.dispatchEvent(new CustomEvent(adblockDetected))
    } else {
      window.dispatchEvent(new CustomEvent(adblockNotDetected))
    }
    // cleanup
    try { s.parentNode.removeChild(s) } catch (e) {}
  }
})()

Notes:

  • Use a short timeout (1–2 seconds) and treat errors as blocked.
  • Create a tiny endpoint programmatically in WordPress to respond with a no-op JS payload.
  • This is generally more robust but can be affected by network errors and proxies, so combine with a bait element.

Server-side fallback (WordPress)

You can add a server-side hook to add a CSS class or inline script to the page when client-side detection is not available. Server-side detection is inherently harder and less reliable for adblockers, so prefer client-side detection with a server fallback to record results (optional).

// Example: functions.php - register a tiny endpoint and enqueue scripts
add_action(init, function () {
// Register a rewrite rule or endpoint for /ads.js
add_rewrite_rule(^ads.js



Acepto donaciones de BAT's mediante el navegador Brave :)



Leave a Reply

Your email address will not be published. Required fields are marked *