EatSmartシステム部ブログ

ウェブサイトの開発や運営に関する情報です。

テンプレートパーツで構成されるサイトのGoogleAdManager実装について-その2

だいぶ前の記事の続きになりますが、以前GAMの広告枠の基本的な実装方法と、ページをテンプレートで分割・再利用している場合の問題点を説明しました。

eatsmart.hatenablog.com

弊社では、defineSlotの空呼び出しが発生しないように実装しているので、紹介します。 GAMの実装(GooglePublisherTag)の詳細は、こちらのドキュメントを参照して下さい。

developers.google.com

流れとしては

  1. googletag.defineSlotで定義されるslotをバッファに格納しておく
  2. ページ上でgoogletag.displayで表示の呼び出しがされるslotを別のバッファに格納しておく
  3. 最終的に、displayで使用されるslotをdefineSlotしてから、広告表示を行う

となります。

0. googletagのMock定義

<script>
    var googletag = {};
    googletag.cmd = {};
    var DFP_DEFINE_SLOTS = {};
    var DFP_DISPLAY_IDS = [];
    var DFP_SIZE_MAPPING = true;

    googletag.cmd.push = function(func) {
       func();
    }
    googletag.defineSlot = function(name, size, id) {
       var slot = {};
       slot.name = name;
       slot.size = size;
       slot.id = id;
       slot.mapping = false;
       slot.defineSizeMapping = function(mapping) {
           slot.mapping = mapping;
           return slot;
       };
       slot.addService = function(val) {};
       DFP_DEFINE_SLOTS[id] = slot;
       return slot;
    }
    googletag.display = function(id) {
       DFP_DISPLAY_IDS.push(id);
    }
    googletag.pubads = function() {
       var pubads = {};
       pubads.enableSingleRequest = function() {};
       pubads.collapseEmptyDivs = function() {};
       return pubads;
    };
    googletag.enableServices = function() {};

</script>

このMockをHTMLのヘッダ部で定義しておくことで、GAMのスロット定義 googletag.defineSlot や広告表示 googletag.display を実行された際に、すぐに処理を行うのではなく、対象の広告枠をDFP_DEFINE_SLOTSやDFP_DISPLAY_IDSという変数に格納する形にします。

1. googletag.defineSlotで定義されるslotをバッファに格納しておく

上記の通りなのですが、0のスクリプトをヘッダ部に置いておくことで、通常HTMLヘッダ部で定義されるGAMのスロット定義

googletag.defineSlot('/XXXXXXX', [[336, 280], [300, 250], [320, 100], [320, 50], [336, 340], [300, 310]], 'div-gpt-ad-XXXXXXXX').addService(googletag.pubads());

が呼ばれた際に、対象の枠がDFP_DEFINE_SLOTS変数に格納されます。

2. ページ上でgoogletag.displayで表示の呼び出しがされるslotを別のバッファに格納しておく

上記の通りなのですが、0のスクリプトをヘッダ部に置いておくことで、通常HTMLBODY部で定義されるGAMの広告表示処理

<div id='div-gpt-ad-XXXXXXXX'>
<script>
googletag.cmd.push(function() { googletag.display('div-gpt-ad-XXXXXXXX'); });
</script>
</div>

が呼ばれた際に、対象の枠がDFP_DISPLAY_IDS変数に格納されます。

3. displayで使用されるslotをdefineSlotしてから、広告表示を行う

最後に、全ての広告枠の googletag.display が呼ばれた後(BODY部の最下部が間違い無いと思います)に、下記のようにDFP_DISPLAY_IDSに入っている枠を正しくdefineSlotしてdisplayすると、ページ内で使用されている枠のみdefineSlotされるので、空呼び出しを防ぐことができます。

<script>
  defineSlotsInner = function() {
    var mapping = googletag.sizeMapping().
      addSize([340,0], [[300,250],[336,280]]).
      addSize([0,0],[[300,250]]).
      build();

    for (var i = 0; i < DFP_DISPLAY_IDS.length; i++) {
      var defineSlot = getSlot(i,DFP_DISPLAY_IDS,DFP_DEFINE_SLOTS);
      if (!defineSlot) {
        continue;
      }

      var func = googletag.defineSlot(defineSlot.name, defineSlot.size, defineSlot.id);
      if (!func) {
        continue;
      }
      if (defineSlot.mapping) {
        func.defineSizeMapping(mapping);
      };
      func.addService(googletag.pubads());
    }

  displayGAMInner = function() {
    for (var i = 0; i < DFP_DISPLAY_IDS.length; i++) {
      googletag.display(DFP_DISPLAY_IDS[i]);
    }
  }

</script>
<script>
  // GAMの広告枠定義が無い場合は、何も処理しない
  if (!DFP_DISPLAY_IDS || DFP_DISPLAY_IDS.length == 0) {
    googletag = {};
    googletag.cmd = [];

    // 処理キューPUT
    googletag.cmd.push(function() {
      defineSlotsInner();

      googletag.pubads().enableSingleRequest();
      googletag.pubads().collapseEmptyDivs();
      googletag.enableServices();

      displayGAMInner();
    });

   if (DFP_DISPLAY_IDS && DFP_DISPLAY_IDS.length > 0) {
       var script = document.createElement('script');
       script.src = 'https://www.googletagservices.com/tag/js/gpt.js';
       script.async = 'async';
       var element = document.querySelector('head');
       element.insertBefore(script, element.firstChild);
   }

}
</script>

この最後の処理のdefineSlotsInnerやスクリプト呼び出しの箇所でprebidやHeader Biddingの処理を入れることで、GAMを使ったHeader Biddingの実装も行うことができます。

ただ、このやり方だと広告処理系スクリプトの呼び出しがHTMLの最後になるので、表示までのレイテンシーが大きく、CoreWebVitalsなどにも悪影響があるかもなと思っています…。