AdBlockを有効にしているブラウザへの対策あれこれ

白状すると私も日常的に広告ブロックツールを使ってますw PC版のChromeではAdBlockPlusの機能拡張を入れ、iOSSafariでは最近AdGuardを利用しています。正直快適でもう手放せませんw

ただこれがサイト運営者の収益を削っているのも事実。せめてサーバ代くらいは捻出したいという方も多いと思いますので今回は広告ブロックの簡易的な検出方法と、その対応策についてまとめたいと思います。

広告ブロックの検出方法

今回利用する方法

例えばGoogle AdSenseは広告を貼り付けたい場所に指定のscriptタグを書いておき、ブラウザからアクセスするとJSが実行されバナーなどが表示されるわけですが、この広告を表示する場所の高さが0pxだったらブロックされたと判定する方法がお手軽です。

<div id="adspace">
  <!-- AdSenseなどのコード -->
</div>

<script>
window.onload = () => {
  const adspace = document.querySelector('#adspace');
  if( adspace.clientHeight === 0 ){
    alert('キャー!広告がブロックされてますわー!! (CV.お嬢様)');
  }
}
</script>

AdSense以外にも応用できますし、処理としても非常にシンプルなので今回はこの原理を利用することにします。

その他

別の方法として良く知られているのは、AdSenseのようにscriptタグを利用するタイプの広告の読み込みでエラーが発生した場合にブロックされたと判定する方法です。恐らく大丈夫だと思うのですがタグを一部改変するのが(規約的な意味で)心臓に悪いので今回は採用しないことにします。

<script id="adspace" async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
 // Googleから指定されたコードがあれやこれや書いてある
</script>

<script>
window.onload = ()=>{
  const adspace = document.querySelector('#adspace');
  adspace.addEventListener('error', (event) => {
    alert('キャー!広告がブロックされてますわー!! (CV.お嬢様)');
  });
}
</script>

また広告ブロックツールによっては、URL中にadsなど特定の文字列が存在するとブロックする特性を利用した方法もあります。ただこの方法だと毎回余計なリクエストが発生するのが気になるのと、環境(ツール)によっては動作しないようなのでこちらも不採用にしました。

/*
 * /js/ads.js
 */
var canRunAds = true;
<script src="/js/ads.js"></script>
<script>
window.onload = ()=>{
  if( window.canRunAds === undefined ){
    alert('キャー!広告がブロックされてますわー!! (CV.お嬢様)');
  }
}
</script>

※いずれもStackoverflowを参考にさせていただきました。

対応策

今回は3つの方法をご紹介します。おすすめは訪問者のストレスが最も少ない3番目です。

その1. アラートを表示する

冒頭のコードとBootstrapなど適当なCSSフレームワークを組合わせれば、広告ブロック中の人に簡単にダイアログを表示することができます。完全にブロックするわけではなく、相手の情に訴えかける作戦ですね。最初はこのくらいで良いのではないかと思います。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf8">
  <title>広告ブロックでアラート表示</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
</head>
<body>

<div id="adspace">
  <!-- AdSenseなどのコード -->
</div>

<section>
  <!-- このサイトの本文 -->
</section>

<!-- モーダルなダイアログ -->
<div class="modal fade" id="modal1" tabindex="-1"
      role="dialog" aria-labelledby="label1" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="label1">広告をブロックしないで🥺</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">×</span>
        </button>
      </div>
      <div class="modal-body">
        このサイトは広告でご飯を食べています。お願いなので広告をブロックをしないで🥺
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-primary">だが断る</button>
      </div>
    </div>
  </div>
</div>
<!-- /モーダルなダイアログ -->

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script>
window.onload = () => {
  const adspace = document.querySelector("#adspace");
  if( adspace.clientHeight === 0 ){
    // ダイアログを表示
    $('#modal1').modal('show');
  }
}
</script>
</body>
</html>

その2. 広告が表示されていればページ内容をAjaxで取得し表示

ブロックされていないことを確認し、別のファイルに保存された本来の内容をAjaxで動的に取得して表示するパターンです。ポイントとなる箇所だけ抜き出して掲載します。

<div id="adspace">
  <!-- AdSenseなどのコード -->
</div>

<div id="article">
  ここに本文が表示されます。しばらく待ちください。<br>
  <small>※広告をブロックしていると表示されません</small>
</div>

<script>
window.onload = async () => {
  const adspace = document.querySelector("#adspace");
  if( adspace.clientHeight > 0 ){
    // URLからファイルを取得 
    const url  = '/page/12345.html';  // 本来の内容があるURL
    const res  = await fetch(url);    // URLからファイルを取得
    const data = await res.text();    // 取得したファイルから情報を取り出す

    // 表示する
    const article = document.querySelector("#article");
    article.innerHTML = data;
  }
}
</script>

気になるのはSEO面ですが、最近のGoogleはこの程度のJavaScriptであれば解釈してくれますので、それほど神経質になる必要はないでしょうか。少なくとも2019年5月時点でGooglebotのChromiumのバージョンは当時最新だった74まで上がっています。これはES2015(ES6)にも対応していることを指します。 webmasters.googleblog.com

それよりもこの方法で気になるのはコンテンツの管理ですね。広告が生命線のサイトでは必要かもしれませんが、PHPなどで動的に管理する仕組みも揃えないとちょっと運用が面倒ですね。また本来の内容が書いてあるファイルを直接覗かれる可能性を考慮し何らかの暗号化をかけるのか…というところまで考えると中々に頭が痛いところですw

その3. 別の内容を表示する

以下ではページ中のadspaceクラスをチェックし、広告ブロックされていれば代わりの内容を表示する物です。表示したい内容は別のファイル(ここでは/mitene.html)に記録しておきます。

ユーザーのストレスは今回紹介した中では一番少なく、サイト運営者からのメッセージも届けやすいので個人的にはこの方法がおすすめです。もともと広告を毛嫌いしているユーザーにここでさらに広告を見せるのは悪手でしょうから、表示する内容は吟味した方が良いと思います。

<div class="adspace">
  <!-- AdSenseなどのコード -->
</div>

window.onload = async () => {
  const url = '/mitene.html';  // 代わりに表示したい内容があるファイル
  let cache = null;

  const adspace = document.querySelectorAll(".adspace");
  for( let item of adspace ){
    if( item.clientHeight === 0 ){  // 広告がブロックされていれば
      if( cache === null ){
        const res = await fetch(url);   // URLからファイルを取得
        const data = await res.text();  // 取得したファイルから情報を取り出す
        cache = data;
      }

      // ファイルの内容を埋め込む
      item.innerHTML = cache;
    }
  }
}

このコードの特徴は広告を埋め込む箇所が複数あったとしても、すべてまとめて書き換えてくれます。また代わりに表示したい内容は最初に取ってきた内容を2回目以降は使いまわしてくれますのでサーバにもクライアントにも優しい作りになっています。ただ別のページに移動すると再取得しますのでもう少しキャッシュ性能をあげたい場合はlocalStorageなどを利用するのがお手軽でしょうか。

Wordpressの場合

広告ブロック対策用のプラグインがあります。私は以下のプラグインを以前利用していました。 wordpress.org

Twitterにも投げましたが、ページが表示される度にブロックされた数をカウントする機能が重たく、このページで紹介したコードに差し替えました。驚くほど軽くなりましたねw 原理が理解できる方は不用意にプラグインを入れない方が良さそうですw

完全にブロックすべきではない

よほどの魅力があるページでなければ、広告ブロックによってコンテンツの閲覧ができなければバックボタンで戻られて終わりです。せっかく何らかの興味を持って来てくれた人にもサイト運営者にとってもどちらにとっても不幸です。実際私もほぼこの行動を取りますので、パッとしない個人のブログ程度で完全にブロックしてしまうのは悪手でしょう。

こういった場合には広告で直接的な利益を得るばかりではなく、その他の方法を検討するのが良いのではないでしょうか。例えばですが以下のような手が考えられます。

  1. ファンになってもらいSNSで拡散をお願いする
  2. コメントに書き込んで盛り上げに協力してもらう
  3. Kindleなどで個人出版した物を案内する
  4. GooglePlayやAppStoreなどにアプリを公開し案内する
  5. 投げ銭で協力を仰ぐ

広告を貼るのは手軽で何も考えなくて済むので楽なのですが、利用者視点からするとウザい広告で溢れかえっている現在の状況ではブロックしたくなるのもわかります。昨今ではプライバシーに対する世の中の目が厳しくっていることもあり、サイト運営者は別の手を考える必要に迫られているのかもしれませんね。

参考ページ