Reactで実装するAdBlock検知 〜ユーザ体験とwebサイト収益の両立のために〜
はじめに
web広告は、無料でウェブサービスを運営するために不可欠な財源です。しかし近年、過剰な広告表示によるユーザ体験の悪化を背景に、多くのユーザが AdBlock拡張機能 や広告ブロック機能付きブラウザを利用するようになりました(参考)。
その結果、広告収益に依存するウェブサイトにとっては 収益減少のリスク が高まり、運営を持続させる上で AdBlockの検知と適切な対処 が重要になりつつあります。
本記事では、Reactプロジェクトで実際に試した AdBlock検知の手法と、検知後のUI実装 について整理します。
AdBlockの仕組みをざっくり整理
広告ブロッカーにはいくつかの方式があります(参考)。
- DNSフィルタリング:広告配信ドメイン自体への通信を遮断
- URLフィルタリング:特定のスクリプトやリソースのURLをブロック
- コンテンツフィルタリング / CSSインジェクション:広告要素を検出し、削除または非表示にする
- JSインジェクション:広告スクリプトの実行を阻止
そのため「検知」するには、要素の非表示状態やリクエストエラーを利用するのが一般的です。
Reactでの検知方法
1. リクエスト方式
既知の広告スクリプトを fetch()
し、失敗すればAdBlock動作中と判断(参考)。
const [adBlockDetectedFromFetch, setAdBlockDetectedFromFetch] =
useState(false);
useEffect(() => {
fetch(
"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
{
method: "HEAD",
mode: "no-cors",
cache: "no-store",
},
)
.then()
.catch((_) => {
console.log(
"Cannot load adsbygoogle.js. Adblock may be active. ",
);
setAdBlockDetectedFromFetch(true);
});
}, []);
2. 要素の表示状態検知
広告要素のスタイルが上書きされていないかを確認する手法。
function useElementVisibility(selector: string) {
const [isPresent, setIsPresent] = useState(false);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const checkElement = () => {
//要素の存在を確認
const el = document.querySelector(selector) as HTMLElement | null;
setIsPresent(!!el);
if (el) {
//要素が存在するなら、そのスタイルを確認
const style = window.getComputedStyle(el);
const rect = el.getBoundingClientRect();
const visible =
style.display !== "none" &&
style.visibility !== "hidden" &&
parseFloat(style.opacity) > 0 &&
rect.width > 0 &&
rect.height > 0;
setIsVisible(visible);
} else {
setIsVisible(false);
}
};
// 初回チェック
checkElement();
// MutationObserverでDOM改変を監視
const observer = new MutationObserver(checkElement);
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true, // style や class 変更も検知
});
// IntersectionObserverで実表示を監視
let intersectionObserver: IntersectionObserver | null = null;
const target = document.querySelector(selector);
if (target) {
intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.target === target) {
setIsVisible(entry.isIntersecting);
}
});
});
intersectionObserver.observe(target);
}
// resize / scroll / visibilitychange でも再チェック
window.addEventListener("resize", checkElement);
window.addEventListener("scroll", checkElement);
document.addEventListener("visibilitychange", checkElement);
return () => {
observer.disconnect();
if (intersectionObserver) intersectionObserver.disconnect();
window.removeEventListener("resize", checkElement);
window.removeEventListener("scroll", checkElement);
document.removeEventListener("visibilitychange", checkElement);
};
}, [selector]);
return { isPresent, isVisible };
}
3. ライブラリ利用
adblock-detect-react
のようなライブラリを利用する手もありますが、ブロッカー側に検知されやすいため、自作判定との併用 が安全です。
実際に検証した環境
主要なAdBlock環境での検知性能を検証しました。
-
AdBlock組み込み型ブラウザ
- Brave
- Vivaldi
-
Chrome拡張
- AdBlock
- uBlock Origin
- AdGuard
- Ghostery
- Privacy Badger
- AdBlock Plus
- AdBlocker Ultimate
-
Firefox拡張
- AdBlock for Firefox
- Adlock
-
Safari拡張
- AdGuard for Safari
紹介した3つの方法はそれぞれ検知できない環境がありましたが、組み合わせることで上記の環境全てで検知に成功しました(2025.08現在)
検知後のUI設計
AdBlockを検知した後の表示には以下のようなものがあります。
モーダル表示
全画面を覆うモーダルで「AdBlockを解除してください」と表示する方式。
確実に目に入りますが、ユーザ離脱のリスクも大きいため、利用は慎重に。
バナー表示
ページ上部や広告枠部分に「このサイトは広告収益で運営しています」と表示。
一度は目に入るが、ユーザ体験を阻害しにくいのがメリット。
{blocked && (
<div className="fixed bottom-0 w-full bg-yellow-200 p-3 text-center shadow-md">
🚫 AdBlockが有効です。このサイトをサポートするため広告解除をご検討ください。
</div>
)}
公式機能の活用
Google Adsense には公式に「AdBlock検知・通知機能」が存在します。
可能であればまずは公式手段を活用するのが安全です。
検証環境の構築
多くのweb開発において、本番環境にデプロイする前にローカルで検証することが多いと思います。しかしながら、Google広告、たとえばGoogle Adsenseはそのままだと登録済みのURLにしか広告を配信してくれません。そこで、ローカル環境で広告を検証するには以下の準備が必要になります。ここではGoogle Adsenseでの方法を書きます.
-
/etc/hosts
を編集し、localhostのaliasとしてdev.<本番環境ドメイン>.com
を追加する。 - Adsenseのタグに
data-adtest="on"
を追加する。これによって収益に反映されないテスト用広告が配信されます。
<ins
className="adsbygoogle"
data-ad-client={登録済みのクライアントID}
data-ad-slot={登録済みのAD SLOT}
data-ad-format="auto"
data-adtest="on" // <- これ!
/>
参考
ユーザ体験を損なわない工夫
-
強制ブロックは避ける
YouTubeのような「広告ブロック解除 or Premium必須」方式は、巨大で多くのユーザが依存しているサービスでない限りユーザ離脱を招き逆効果になるかもしれません。
-
1度だけ訴求する
モーダルのような画面占有率の高いメッセージを何度も出すのは不快要因になりやすいため、CookieやLocalStorageで制御(参考)
-
透明性の確保
「広告収益で運営しているためご協力ください」と伝える方が、ユーザ理解を得やすい。
今後の展望
- サーバーサイド広告挿入(SSAI):動画配信で広がる技術。クライアントでのブロックは困難。
- Acceptable Ads対応:AdBlock Plusなど一部は「許容可能な広告」枠を用意しており、規格準拠すれば表示される可能性もある。
- 課金・寄付モデルとの併用:The Guardian や ニコニコ動画のように、広告以外の収益源を提示するのも重要。
まとめ
- AdBlockはユーザにとって利便性がある一方、サイト運営にとっては死活問題。
- Reactでは、要素の表示状態チェック方式・リクエスト方式・ライブラリ利用を組み合わせることで多くの環境で検知が可能。
- 検知後は、モーダルよりもバナー、強制よりも依頼 の方がユーザ体験を損なわない。
- 公式機能やサーバーサイド手法、寄付モデルなども検討できる。
Discussion