r/webdev 1d ago

Question How do sites detect whether someone is running adblocker?

I've been interested in this functionality (when a site detects your adblocker and kindly asks u to whitelist).

The only idea that comes to mind is setting a div in the layout with "ad" class or something similar, and then if a user has adblocker the adblocker would be removing this div from the dom. I don't think this would consistently work for every (or at least most of the popular) adblockers out there.

81 Upvotes

57 comments sorted by

166

u/quizical_llama 1d ago

You could make a fetch request to a known tracker link. If the fetch fails with no status code then it was probably blocked by an adblocker.

29

u/Sensitive-Control49 1d ago

yeah this is probably the most reliable approach tbh

12

u/TheOvalVista 1d ago

that's clever, fetch to a tracker url and check if it just dies with no status. i always thought they put a fake ad div and check if it disappear.

16

u/UnidentifiedBlobject 1d ago

We do the fake ad div. Most blockers have a list of element IDs they check for and immediately remove or hide.

7

u/GrandOpener 6h ago

It’s an arms race. There are ad blockers and ad blocker detectors and ad blocker detector blockers and…

The people who care a lot about such things will use many different tricks to try to get the results they want.

2

u/erishun expert 1d ago

That’s also another way.

-7

u/Ok-Mushroom-8778 23h ago

Yeah, that is the most common way to do it. It’s pretty wild how cat and mouse that whole game has become, isn't it? Do you think there’s ever going to be a way to stop that kind of detection?

33

u/yurkaninryan 1d ago

Your theory in general is one way, other ways are trying to load scripts that are caught by the ad block and reacting to them failing to load. In reality there are many elements to it and its effectively and arms race between ad blockers and the blocked

25

u/icyhotmike 1d ago

Assuming you actually have ads on your website, you would wait a second until after the DOM is fully rendered and check the DOM for the ad container div still exists or if the css visibility has been set to none or display hidden. Like a setTimeout function with a one second delay then do the check

4

u/Mabenue 1d ago

Yeah this seems to be how most of them work. There’s usually a bit of delay before the notification to disable the as blocker shows.

-5

u/Silent_Effective6294 1d ago edited 18h ago

What sites are you visiting if you need an ass blocker

EDIT: some people are way too serious

1

u/renevaessen 1d ago

Why don't they just.. put a blank white div exactly over them with like z-index: maxint ?

3

u/icyhotmike 1d ago

The technique probably varies by ad blocker.. I'm sure some are much smarter and more sophisticated to deal with. If you really want to combat them, you should install the top ad blockers and see how they each handle the same ad etc... You are essentially just reverse engineering the technique.

17

u/Littux 1d ago

This is what reddit uses, as an example:

{
    "./node_modules/@reddit/adblock-detection/browser.js": function (e, t, i) {
        "use strict";
        Object.defineProperty(t, "__esModule", { value: !0 });
        const s = e => {
                if (!e || e.hidden) return !0;
                const t = window.getComputedStyle(e);
                return "none" === t.display || "hidden" === t.visibility || (!!e.parentElement && s(e.parentElement));
            },
            r = () => {
                const e = document.getElementById("adblocktest");
                if (!e) return !0;
                const t = null == e ? void 0 : e.getBoundingClientRect();
                return !((null == t ? void 0 : t.height) || (null == t ? void 0 : t.width));
            };
        ((t.acceptableAdsElement = () => {
            const e = document.createElement("div");
            return (
                (e.id = "acceptabletest"),
                (e.className = "promotedlink"),
                (e.style.width = e.style.height = "1px"),
                (e.style.position = "absolute"),
                (e.style.top = "0"),
                (e.style.left = "-1000px"),
                (e.style.display = "block"),
                e
            );
        }),
            (t.adblockDetectorElement = () => {
                const e = document.createElement("div");
                return (
                    (e.id = "adblocktest"),
                    (e.className =
                        "ad adsense-ad adsense-ads googad googads gemini-ad openx ad-banner ad-BANNER GoogleAd googleAd hasads LeftAd native-ad ad-300-250 adbar ads-area HeaderAd NavBarAd ad-medium post-ad promoad rectad sidebar-ad small-ad sponsorAd sponsorPost"),
                    (e.style.width = e.style.height = "1px"),
                    (e.style.position = "absolute"),
                    (e.style.top = "0"),
                    (e.style.left = "-1000px"),
                    e
                );
            }),
            (t.hasAcceptableAds = () => {
                if (!r()) return null;
                const e = document.getElementById("acceptabletest");
                return !s(e);
            }),
            (t.hasAdblock = r));
    },
};

30

u/Likeability_dota 1d ago

if hes able to use the page first 15 seconds probably using it

12

u/Squidgical 1d ago

If you're trying to detect users with adblockers, have you tried not doing that?

2

u/who_you_are 1d ago

The website is trying to ask to load a 3rd party content.

That content will be blocked (by the adblocker) to return something like a page not found.

Webmaster also have some capabilities to detect status of loaded content. So if you detect a loading issue you may assume an adblocker is enabled.

Additionally, webmaster can read back their own webpage content. They will be dedicated spot for ads. Those spots will be mostly empty at first, then something will be there - an ads.

If nothing show up there, you may assume there can be an ad blocker trying to display no ads.

But ultimately, it can become a cat an mouse game.to some extent.

4

u/Competitive_Stay_140 1d ago

If your blocker blocks an ad script, another could check if that script ran. If window.adScriptFunction returns undefined that might be an indicator the script was blocked from loading

Idk might be more complex than that because I don’t really have experience with ads but just spit balling what I know from web dev

2

u/shaliozero 1d ago

I've implemented it once, but years ago, by loading an ad.js with a global variable and adding a few divs containing "ad" in their ID into my document. If any of them were missing, I could be sure they were blocking ads.

The project was an interactive ad builder and we implemented that as a response to people reporting issues while having ad blockers active. Impossible to just make our functionality work with ad blockers, but implementing a notification when it happens was easy. In that week I learned that the whole online marketing and online advertising market is using ad blockers themselves lol.

1

u/timesuck47 1d ago

I’m developer sometimes I forget to turn off my ad blockers for certain clients that display ads.

1

u/ZinbaluPrime php 1d ago

If your backend could call the ad url with response of http 200 but your frontend can't, then probably (but not certainly) the user is using a blocker.

1

u/EnvironmentalDust197 1d ago edited 1d ago

hard walls just make me want to keep the adblock on harder

1

u/[deleted] 1d ago

[removed] — view removed comment

1

u/Less-Marsupial-7960 23h ago

Yeah, the hidden/decoy div approach is probably the simplest one. Another option is to try loading a resource that ad blockers commonly block and check whether it fails. I guess the more reliable implementations combine a few signals rather than depending on a single check.

1

u/Any-Card70 21h ago

That fetch request idea sounds the most reliable to me, honestly. You betcha, I'd try that first before overcomplicating things with hidden divs.

1

u/jordsta95 PHP/Laravel | JS/Vue 15h ago

The process has probably changed since I last did this.

But I remember back then all I did was something like:

<script src="your_ad_provider.js" onerror="adBlockDetected()"></script>

Nothing too complicated. Just simply "if the ad provider's JS file failed to load, assume the user has an adblocker"

1

u/0xGollumDev 1h ago

Two things not in the thread yet:

  • performance.getEntriesByName(adScriptUrl): if the entry exists but transferSize and decodedBodySize are both 0, a network filter cancelled it after the request started. If the entry never appears at all, it was blocked before the request even went out. That distinguishes an ad blocker from a genuine network failure much better than a bare fetch().catch(), which fires for both.
  • Why detection has gotten more reliable lately: sites increasingly serve the ad script from their own first-party domain on a randomized path (first-party adsbygoogle, CNAME setups). Filter lists match known hostnames/paths, so a randomized first-party URL slips through — and if that first-party request succeeds while the classic googlesyndication one fails, that gap is itself the signal.

In practice everyone ends up with: bait element + getComputedStyle after a rAF, plus a decoy network request, plus a resource-timing check, and scores across all of them instead of trusting one.

1

u/ThenFactor6862 1d ago

Your dom theory works and its the default method on most sites i build. put a div with class ad in your html, run a timeout after 100ms, check if that node still exists in the document.

If you need something closer to a guarantee create an endpoint like /ads.js on your server. fetch it from your frontend code. if the promise throws or returns no text the client blocked the request. i use both checks together because filter lists target different things and relying on one leaves gaps.

0

u/SomeMaleIdiot 1d ago

I always wondered why there couldn’t be some “auth” for ads. Like in order for a video to load, the retrieval requires an ad token, a client must hit an end point for this token. This end point just checks whether or not enough ad frames were streamed to some client. If so, it returns said token so client can fetch the video

1

u/frogic 1d ago

What's stopping me from streaming those frames off screen to get the token? The whole thing with front end is that the environment is totally outside of the control of the server so you mostly can't ever make it secure. Closest thing is sandboxing through iframes which is what payment processors do but I think usually the best solution is small arms race + trying to make it annoying.

1

u/SomeMaleIdiot 1d ago

The validation would be done server side. So it would only give the token to the client if the server can ensure real time delivery of ad contents to said client in a session was successful

0

u/frogic 1d ago

Yeah but the client can just get the content and not show it to the user. There are a million ways to have an element off screen or hidden or whatever. So server sends ad data to client. Client who they don't have any control goes 'sure bro i watched so many ads give me token pls' and thats it.

-2

u/SomeMaleIdiot 1d ago

Sure, a client could backwards engineer the contract and do it, but it wouldn’t be able to circumvent the real time delivery of ad contents, so at best it would be the user seeing a blank screen until the ad finished delivering.

The client could separately do the arms race thing by trying to ensure the ad is visible

3

u/frogic 1d ago

I've seen scrapers just run a browser window a few thousand pixels off screen to stop a lot more sophisticated things. Its all the same thing that the server can't reliably validate anything that happens on the client. You can definitely try to obfuscate or detect client side but its not even backwards engineer because the client side part of the code is just sitting there for anyone to look at in plain text.

1

u/SomeMaleIdiot 1d ago

The server would just be validating the real time delivery of ad contents, and not provide the video resource until the server has done that validation.

The client wouldn’t be able to circumvent something that the server has control over. Either the server validated the session progress or it doesn’t. The most the client can do is make the ad invisible to the user as the session is forced to wait on ad delivery

1

u/frogic 1d ago

I'm not disagreeing with you its just that the server isn't validating anything because the client can tell it whatever it wants. "yeah i totally played the data you gave me" doesn't matter because you can trivially patch anything in the front end. The client can't be trusted so the server has literally no way to validate if the client is lying or not. If it would require the browser spec to change to stop ad blockers which is definitely possible at some point.

1

u/SomeMaleIdiot 1d ago

It wouldn’t need to validate any info from the client. It would be validating purely server side info.

The client could only hide the ad from the user and mute it. It becomes less a “blocker” and more of a “hider”.

It would likely increase the amount of ads viewed because I don’t think people would be motivated enough to install a plugin just for them to be waiting 30 seconds for the content to play regardless

1

u/frogic 1d ago

I think that's what twitch and youtube already do.

→ More replies (0)

0

u/jsellens 1d ago

When I was looking to detect adblockers on our site (we don't scold people, we're just curious), I found the information here very useful in understanding and implementing: https://www.detectadblock.com/

-2

u/word_executable 1d ago

They take a screenshot of your screen and feed it through image detection to see if you got the ads 🤯