A Non-Blocking Ad-Block Notice with Bounded Detection
# How bait state, script lifecycle, grace periods, and bounded observers detect ad-delivery failures while keeping the article readable and offering retry or dismiss actions.
Ad-block detection is a poor access-control boundary because the same browser signals can also come from network errors, CSP, offline use, or an ordinary loading delay. This site keeps the article readable when ads cannot be verified and shows a compact notice with retry and dismiss actions. The decision is implemented as a bounded state machine rather than a one-shot DOM check.
This is not a guide to evading or disguising ad delivery. It documents how the site reduces false positives while preserving the reader's choice.
Bounded state machine combining ad-script load or error, grace timers, bait checks, and a final ad or non-blocking notice state
*Diagram: combine script lifecycle with bounded grace checks instead of treating DOM presence as proof. The article remains open in either branch.*
Why the notice is not a full-page gate
An ad script can fail because of an extension, DNS filtering, a managed network, CSP, offline state, or a routine loading delay. Browser-side signals cannot prove the cause or identify a particular extension. Blocking the article on an uncertain signal would also penalize readers who already allow ads.
The notice is therefore a small panel fixed near the lower-right edge. The article and navigation behind it remain usable. It uses role="status" with aria-live="polite"; it does not claim modal semantics, trap focus, or make the document inert.
Four signals used by the implementation
Check whether an ad-like bait element becomes display:none, visibility:hidden, or zero-sized.
Record the AdSense loader's load and error lifecycle instead of checking only whether a script node exists.
Re-evaluate after 450 ms, 1500 ms, and 3500 ms rather than deciding immediately after hydration.
Clear the notice if a delayed loader later becomes healthy.
A script node can remain in the DOM after a network error. Conversely, consent or runtime settings can insert the loader after hydration. Presence alone is not sufficient evidence, so the implementation combines several signals for a finite period.
Two actions remain with the reader
The notice offers “Retry ads” and “Keep reading.” Retry reloads the page so the ad loader is evaluated from a clean start. Keep reading dismisses only the notice and does not alter the article.
Detailed allowlisting steps stay collapsed unless the reader asks for them. The copy does not claim that a particular extension is installed. If the reader chooses to allow ads, it suggests limiting the allowlist entry to this host.
Bound every observer
The MutationObserver watches document.head, not the entire article body, and disconnects after five seconds. Timers, observers, listeners, and the bait node are all released on unmount. An unbounded body observer would react to unrelated article mutations and make the behavior harder to predict.
Retry uses window.location.reload() to reload the page and run the same detection sequence from the beginning. It does not add a retry marker to the script URL or obfuscate URLs or class names to bypass blockers.
UI and policy boundaries
The notice explains that ad delivery supports the blog, but it never asks readers to click an ad or disguises advertising as navigation. The detection result is not used to infer an extension name, identify a visitor, or create a fingerprint.
If an AdSense recovery message is also enabled, it should not be layered over the custom notice without checking the live AdSense configuration. The final setup should remain consistent with this site's non-blocking policy.
Regression contract
No notice before the grace period.
No notice when the bait is visible and the loader completes.
A script element that fires error produces an ad-delivery notice.
A delayed healthy loader clears the notice.
Head observation stops after its deadline and on unmount.
The notice is exposed as a polite status and has no modal semantics.
“Keep reading” dismisses only the notice.
This contract does not guarantee that an ad will always render. It keeps the detector's resource use bounded and prevents an uncertain delivery signal from holding the article hostage.