テンプレートパーツで構成されるサイトのGoogleAdManager実装について-その2
だいぶ前の記事の続きになりますが、以前GAMの広告枠の基本的な実装方法と、ページをテンプレートで分割・再利用している場合の問題点を説明しました。
弊社では、defineSlotの空呼び出しが発生しないように実装しているので、紹介します。 GAMの実装(GooglePublisherTag)の詳細は、こちらのドキュメントを参照して下さい。
流れとしては
- googletag.defineSlotで定義されるslotをバッファに格納しておく
- ページ上でgoogletag.displayで表示の呼び出しがされるslotを別のバッファに格納しておく
- 最終的に、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などにも悪影響があるかもなと思っています…。