この記事は GMOアドマーケティング Advent Calendar 2020 9日目の記事です。
こんにちは、GMOアドマーケティングの主にめるもとGMOSSP周りのフロント周りを開発しているY.A.です。
今回は「Google Ad Manager(以降GAM)x Prebid.js」というHeader Biddingではよくある構成について、基本的な仕組みの説明とデバッグ・不具合調査方法をお伝えしたいと思います。
※これは筆者のデスクトップからキャプチャを取った画像です。以下同様です。
そもそもPrebid.jsの導入・運用するにあたって、なかなかハードルを感じている担当者も多いのではないでしょうか。
理由は、担当者に以下の知識を求められるためでしょう。
1) GAMの理解
2) Prebid.jsの理解
片方を押さえている広告運用担当者/開発担当者はいるかと思いますが、その両方を中級者レベルで分かっている担当者はそう多くないはずです。(かくいう私もGAMの仕組みを理解するのにとても苦労しました。)
Prebid.jsはこの1、2どちらもある程度理解していないと、導入を始め、その後の安定的な運用もなかなか難しいです。
本記事ではその両方の間に立つような形で、GAMとPrebid.jsの両方の基本的な仕組みと、そこからPrebid.jsがGAMに対してどのように動いているかを説明したいと思います。
対象読者は媒体担当者の方で、例えば次のような方を想定しています。
- GAMは分かるがPrebid.jsがよく分からない広告運用担当者
- Prebid.jsのドキュメント、ソースは読めるがGAMがよく分からない開発担当者
- どちらもよく分からないが、押さえておくべきポイントについて知りたい方
Prebid.jsベースのラッパーを利用されている方にとっても、今回説明する内容でもって「どのように動いているのか」「不具合があるときどこを見ていけば良いのか」が分かるようになると思います。
なお、そもそもGAMとは何かHeader BiddingやPrebid.jsが何か、などの説明は省略します。
また一旦概要を掴んでもらうことを目的とした構成としているため、あまり詳細には触れておりませんので、あらかじめご了承ください。
【見出し】
【前提1】 GAMの仕組み・設定
まずGAM経由で広告を配信するための設定を説明します。
基本的な設定
1. 広告ユニットの作成
場所: 「在庫」 > 「広告ユニット」
Webページに貼る枠です。英語では「ad unit」です。
作成しましたらタグを発行し、ページへ貼ります。headとbody内にそれぞれ必要です。
2. 広告申込情報の作成
次に広告申込情報を作成します。
広告申込情報とは何の広告クリエイティブを、どこに、どのような条件で表示するのかを設定するものです。 英語では「line item」です。
次の手順で作ります。
2-1. オーダーの作成
場所: 「配信」 > 「オーダー」
オーダーとは広告申込情報を束ねるものです。大まかに広告申込情報の分類として使われます。
例えばPrebid.js用の広告申込情報であれば「prebid」などの名前でオーダーを作ります。
2-2.オーダーに紐づく広告申込情報の作成
オーダーに紐づく申込情報を作ります。
広告申込情報は、広告配信条件を定義するものです。具体的には何を優先するかのタイプや、その他配信条件(日時、枠、Key-Valueの条件)を設定します。
「広告申込情報タイプ」「想定されるクリエイティブのサイズ」「配信設定」「配信の調整」「ターゲティングを追加」などを入力していきます。
ちなみに「ターゲティングを追加」はPrebid.jsとの連携を理解する上で重要になってきます。後ほど詳細を説明します。
2-3. クリエイティブの作成
2-2. で作成した広告申込情報の条件で出すクリエイティブを設定します。
3. オーダーの有効化
ここまでできたら配信したいタイミングでオーダーの「承認」ボタンをクリックします。
これにより配信されるようになります。
なおステータスが変更されるまで時間がかかります。
なかなか設定が反映されないため「何か設定誤ってるかな」といじくり回すと泥沼に入ってしまうので注意してください。10分かそれ以上かかると考えておいた方が無難です。
以上までがGAMの仕組みおよび設定方法の基礎知識です。
ただPrebid.jsとの連携を理解するためには「2. 広告申込情報の作成」の「ターゲティングを追加」、つまりGAMのカスタムターゲティングの理解が不可欠ですので、そちらも説明します。
広告申込情報設定の応用 「Key-Value」を使ったカスタムターゲティング
カスタムターゲティングとは、ユーザーが任意の条件で広告申込情報を出し分けしたいケースで使用するものです。その設定には「Key-Value」を使用します。
例えばページの種類としては同じ記事ページであっても、その記事が属するカテゴリ毎に広告を出し分けしたい、といったケースがあるとします。
カスタムターゲティングであれば、「Key」に「category」を設定し、次に「Value」に「entertainment」が入る場合はAという広告申込情報、「fashion」が入る場合はBという広告申込情報、といった設定をすることができます。
それでは、「Key-Value」を使ったカスタムターゲティングを実現するにはどうすればよいかというと、次の設定が必要です。
- 「Key-Value」にて値の設定
- 広告申込情報にてカスタムターゲティングの設定
- 広告タグにて設定
1. 「Key-Value」にて値の設定
Key-Valueの値についてはあらかじめ定義が必要です。
場所: 「在庫」 > 「Key-Value」
2. 広告申込情報にてカスタムターゲティングの設定
広告申込情報の下に「カスタムターゲティング」欄があるので、そこで設定します。
3. 広告タグにて設定
広告枠のタグ発行時にもKey-Value指定ができますが、既存のhead内に埋め込む枠定義の箇所に次のメソッドを追加することでもできます。
1 |
setTargeting("Key", "Value"); |
以下広告枠単位でのKey-Valueの設定です。
(before)
1 |
googletag.defineSlot('XXXXX', [[1, 1], 'fluid'], 'XXXXX').addService(googletag.pubads()); |
(after)
1 |
googletag.defineSlot('XXXXX', [[1, 1], 'fluid'], 'XXXXX').addService(googletag.pubads()).setTargeting("Key", "Value"); |
以上がKey-Valueを使ったカスタムターゲティングのやり方です。
そしてこのKey-ValueこそがPrebid.jsとの連携において重要な役割を担っています。
後半で解説しますので、覚えておいてください。
詳しいPrebid.js向けのGAMの設定手順については、Prebid.jsのドキュメントにもあるのでご覧ください。(説明に使われている少しUIのスクショは古いですが今でも有効です。)
https://docs.prebid.org/adops/step-by-step.html
https://docs.prebid.org/adops/send-all-bids-adops.html
【前提2】 Prebid.jsの仕組み・設定
Prebid.jsのソースの設定を説明します。
Prebid.jsのダウンロード
Prebid.js導入にあたってはまずPrebid.jsのソースを読みこむようにしないといけません。
まず公式のページでそのソースをダウンロードします。
セレクトからバージョンを選びます。そして追加したいビッダーのチェックボックスにチェックを入れ、押すことでページに設定したいPrebid.jsのソースがダウンロードできます。
直感的で分かりやすかったかと思いますが、これ以外にもPrebid.jsのソースを用意する方法があります。GithubにあるPrebid.jsのリポジトリをcloneして、コマンドからビルドする方法です。
こちらのやり方の利点としては、modules.jsonにビッダーを配列で入れておけばそのファイルを元にビルドしてくれるので、ビッダーの管理が楽になることです。
1 |
gulp build --modules=modules.json |
詳しくはREADMEをご参照ください。
Prebid.jsの設定ファイル
いずれかの方法で取得したPrebid.jsを媒体のページに設置しましたら、次に設定のscriptを書きます。
設定scriptにはPrebid.jsを開始したい枠の指定、ビッダー情報などを定義します。
Prebid.jsドキュメントページにて、サンプルで公開しているscriptに説明コメントを追記しましたのでご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
<script> // 広告サイズ var sizes = [ [300, 250] ]; // bidderのタイムアウト var PREBID_TIMEOUT = 1000; // Prebid.jsがloadされなかった場合のタイムアウト var FAILSAFE_TIMEOUT = 3000; // GAMの広告枠とPrebid.jsのビッダーの連携 var adUnits = [{ // GAMの枠 code: '/19968336/header-bid-tag-1', // メディアの種類 mediaTypes: { banner: { sizes: sizes } }, // ビッダーの設定オブジェクトを配列で入れていく // どのようなパラメータが必要かは各種ビッダーによって異なるためPrebid.jsのドキュメントを確認する // https://docs.prebid.org/dev-docs/bidders.html bids: [{ bidder: 'appnexus', params: { placementId: 13144370 } }] }]; // ======== DO NOT EDIT BELOW THIS LINE =========== // var googletag = googletag || {}; googletag.cmd = googletag.cmd || []; googletag.cmd.push(function() { // GAMの広告リクエストを止める(Prebid.jsのビッダーリクエスト・レスポンスを先に行いたいため) googletag.pubads().disableInitialLoad(); }); var pbjs = pbjs || {}; pbjs.que = pbjs.que || []; pbjs.que.push(function() { // 先のadUnitsを登録 pbjs.addAdUnits(adUnits); // Prebid.jsのリクエスト pbjs.requestBids({ // ビッダーのレスポンスが返ってきたorタイムアウトに差し掛かった場合のcallback bidsBackHandler: initAdserver, // タイムアウト timeout: PREBID_TIMEOUT }); }); function initAdserver() { if (pbjs.initAdserverSet) return; pbjs.initAdserverSet = true; googletag.cmd.push(function() { // GAMにKey-Valueターゲティングを行う pbjs.setTargetingForGPTAsync && pbjs.setTargetingForGPTAsync(); // disableInitialLoad()で止めていたリクエストを再開 googletag.pubads().refresh(); }); } // in case PBJS doesn't load setTimeout(function() { initAdserver(); }, FAILSAFE_TIMEOUT); // GAMの通常のheadの設定 googletag.cmd.push(function() { googletag.defineSlot('/19968336/header-bid-tag-1', sizes, 'div-1') .addService(googletag.pubads()); googletag.pubads().enableSingleRequest(); googletag.enableServices(); }); </script> |
ここでのポイントは「googletag.pubads().disableInitialLoad()」と
1 2 |
// GAMの広告リクエストを止める(Prebid.jsのビッダーリクエスト・レスポンスを先に行いたいため) googletag.pubads().disableInitialLoad(); |
「pbjs.setTargetingForGPTAsync」、および「googletag.pubads().refresh」です。
1 2 3 4 |
// GAMにKey-Valueターゲティングを行う pbjs.setTargetingForGPTAsync && pbjs.setTargetingForGPTAsync(); // disableInitialLoad()で止めていたリクエストを再開 googletag.pubads().refresh(); |
これらが先に説明したGAMのKey-Value設定に関わってきます。
この後の「GAMとPrebid.jsの連携」で説明します。
なお公式ドキュメントに先のサンプルのフルHTMLが載っていますので、詳細はそちらを参照ください。
GAMとPrebid.jsの連携
以上までを設定することで、ページ上では次のことが起きます。
- head内に設定されたPrebid.jsおよび、設定scriptからビッダーへリクエスト
- ビッダーからのレスポンスをPrebid.jsが受ける
- Prebid.jsが設定に応じてデータを整形し、複数あるビッダーのなかで勝者のビッダーのレスポンスをキャッシュ
- Prebid.jsがKey-Valueの形で勝ったビッダーをGAMに通知
- GAMがそのKey-Valueをもってマッチする広告申込情報を探し、他の広告申込情報と比較
- GAMが4.のビッダー広告申込情報がオークションに勝ったと判定したら、Prebid.jsに通知しGAMの枠にクリエイティブが描画
全体のイメージ図についてはPrebid.jsの公式に掲載されている画像参照ください。
https://docs.prebid.org/overview/intro.html
この一連のフローの中でも、特に「GAMとPrebid.jsの連携」を理解する意味でポイントとなるのは、4.~6.までの動きです。
4.~6.までの流れを技術面で詳しく見ていきましょう。
4 . Prebid.jsがKey-Valueの形で勝ったビッダーをGAMに通知
GAMでKey-Valueの設定タグでに行うには通常次のようにすると説明しました。
1 |
googletag.defineSlot('XXXXX', [[1, 1], 'fluid'], 'XXXXX').addService(googletag.pubads()).setTargeting("Key", "Value"); |
しかし先ほどのPrebid.jsのコードを見てもらうと分かりますが、該当しそうなところにその命令が見当たりません。なぜでしょう。
1 2 3 4 5 6 |
googletag.cmd.push(function() { googletag.defineSlot('/19968336/header-bid-tag-1', sizes, 'div-1') .addService(googletag.pubads()); googletag.pubads().enableSingleRequest(); googletag.enableServices(); }); |
理由は、Prebid.jsが独自のAPIでGAMのKey-Valueを設定しているからです。
Preibid.jsの設定script内に「pbjs.setTargetingForGPTAsync();」という命令があります。これはGAMにKey-Valueのターゲティングを行うAPIです。
https://docs.prebid.org/dev-docs/publisher-api-reference.html#module_pbjs.setTargetingForGPTAsync
1 2 |
// GAMにKey-Valueターゲティングを行う pbjs.setTargetingForGPTAsync && pbjs.setTargetingForGPTAsync(); |
この命令を呼び出すことでsetTargeting()を使わず、その枠に設定してある複数のビッダーのなかから、勝者のビッダーだけをKey-Valueの形で付与できます。
ただKey-Valueターゲティングをちゃんと設定するには、一旦GAMのリクエストを止めないといけません。そのため、冒頭の方でGAMの広告リクエストを止める「googletag.pubads().disableInitialLoad();」のAPIを実行しています。
そして「pbjs.setTargetingForGPTAsync();」をした後は、「googletag.pubads().refresh();」で広告リクエストを再開させます。
これが先のPrebid.jsの設定scriptの意味です。
1 2 3 4 5 6 7 8 9 10 |
// GAMの広告リクエストを止める(Prebid.jsのビッダーリクエスト・レスポンスを先に行いたいため) googletag.pubads().disableInitialLoad(); ... // GAMにKey-Valueターゲティングを行う pbjs.setTargetingForGPTAsync && pbjs.setTargetingForGPTAsync(); // disableInitialLoad()で止めていたリクエストを再開 googletag.pubads().refresh(); |
5. GAMがそのKey-Valueをもってマッチする広告申込情報を探し、他の広告申込情報と比較
コード上GAMに対してKey-Valueを付与するようになっていても、肝心のGAM側で、事前にそれらKey-Valueを受け止める広告申込情報を用意できていないと意味がありません。
そのためまずGAMで「Key」として「hb_pb」を作る必要があります。「hb_pb」とはPrebid.jsがデフォルトで送るKeyです。
そしてビッダーが返してきた少数第二位までの「Value」を用意します。例えば¥150であれば150.00といった具合です。
Prebid.jsは仕様として、少数第二位まで定義しないといけません。
あとはビッダーが返すcpmのレンジ分だけValueとそれを設定する広告申込情報を作るだけです。(ちなみにこれがかなりの数必要になるのは容易に想像つくかと思います。)
これでPrebid.jsのAPIによってKey-Valueが付与されると、GAMのほうで用意した広告申込情報とマッチされるようになります。
6. GAMが4.のビッダー広告申込情報がオークションに勝ったと判定したら、Prebid.jsに通知しGAMの枠にクリエイティブが描画
Prebid.jsからGAMに渡されたKey-Valueは、該当広告申込情報にセットしたクリエイティブにて、レンダリングされます。
セットするクリエイティブコードは以下です。
マクロを使って自動的にValueの値が変数にセットされて実行されるのが、見て取れると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script src="https://cdn.jsdelivr.net/npm/prebid-universal-creative@latest/dist/creative.js"></script> <script> var ucTagData = {}; ucTagData.adServerDomain = ""; ucTagData.pubUrl = "%%PATTERN:url%%"; ucTagData.targetingMap = %%PATTERN:TARGETINGMAP%%; ucTagData.hbPb = "%%PATTERN:hb_pb%%"; try { ucTag.renderAd(document, ucTagData); } catch (e) { console.log(e); } </script> |
以上までが4.~6.の「GAMとPrebid.jsの連携」の大きな流れです。
まさに記事冒頭であげた「GAMが分かる」「Prebid.jsが分かる」だけでは全体は掴めない、というのが実感できたのではないでしょうか。どちらも分かってこそ初めてGAMとPrebid.jsの連携の仕組みが理解できるかと思います。
そしてこれが分かることでぐっとデバッグにも自信が持てるはずです。
ではここまでの理解を元に、最後に各種デバッグ方法について見てみましょう。
各種デバッグ方法
GAMとPrebid.jsが適切に設定できたか、あるいは不具合が出た場合の確認方法を説明していきます。
各ビッダーのレスポンスとGAMでのレンダー結果の確認方法
GAMとPrebid.jsが設定できたら、ビッダーサーバーと疎通(リクエスト・レスポンス)ができるようになったはずです。
しかしそれを確認するにはどうすれば良いでしょうか。
Prebid.jsを読み込んでいる場合、「pbjs」というグローバル変数が読み込まれます。
このpbjsに各種APIが提供されています。
以下命令はPrebid.jsの設定scriptで設定されたGAM枠とビッダー、そのビッダーから返されたレスポンス(cpmなど)をChromeなどのDevToolsに表示させるものです。
試しにChromeのConsoleパネルを開いて次のscriptをコピペして、Enterを押して実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
(function() { function forEach(responses, cb) { Object.keys(responses).forEach(function(adUnitCode) { var response = responses[adUnitCode]; response.bids.forEach(function(bid) { cb(adUnitCode, bid); }); }); } var winners = pbjs.getAllWinningBids(); var output = []; forEach(pbjs.getBidResponses(), function(code, bid) { output.push({ bid: bid, adunit: code, adId: bid.adId, bidder: bid.bidder, time: bid.timeToRespond, cpm: bid.cpm, msg: bid.statusMessage, rendered: !!winners.find(function(winner) { return winner.adId==bid.adId; }) }); }); forEach(pbjs.getNoBids && pbjs.getNoBids() || {}, function(code, bid) { output.push({ msg: "no bid", adunit: code, adId: bid.bidId, bidder: bid.bidder }); }); if (output.length) { if (console.table) { console.table(output); } else { for (var j = 0; j < output.length; j++) { console.log(output[j]); } } } else { console.warn('NO prebid responses'); } })(); |
すると次のようなテーブルが出るはずです。
このテーブルではビッダーが設定されているGAMの広告枠とそのビッダーのcpm、GAM内で勝ってレンダーされた結果などが確認できます。
これによってリクエスト・レスポンスを確認できます。
もしここでリクエスト・レスポンスを確認できない場合、ビッダーから提供されたIDに誤りがあるか、タイポ、あるいはJSで設定するのでシンタックスエラーが起きている可能性があります。
シンタックスエラーであればConsoleパネルを確認、エラーがなければビッダーにIDが有効になっているか確認をしてみましょう。
または、それ以前にそもそもPrebid.jsダウンロード時に該当ビッダーを含めていない可能性もあります。その場合も同様のことが起こりますので、ご注意ください。
なお毎回前述のscriptをConsoleに打つのは面倒なはずです。
Prebid.jsのドキュメントではSourcesパネルにあるSnippetの利用を勧めているので、通常はそちらの方をご使用ください。
https://docs.prebid.org/dev-docs/troubleshooting-tips.html
Snippetについては以前私が執筆したDevToolsの記事でも紹介していますので、よろしければご参考にしてみてください。

Key-Valueの付与調査
GAMとPrebid.js連携においてGAMのKey-Valueが使用されると説明しました。
これは別の言い方をすると、Prebid.jsがビッダーサーバーとのリクエスト・レスポンスが正常に行われ、勝者が計算されたとしても、GAMに対してKey-Valueの付与がきちんとされないと動かないことを意味します。
もし前述のビッダーサーバーとのリクエスト・レスポンスに問題がない場合は、Key-Valueの付与が正常に行われているかを確認する必要があります。
ここでその確認に使えるのが「?pbjs_debug=true」と「googletag.openConsole()」です。
pbjs_debug=true
見てもらうと分かりますが、Prebid.js内での処理経過が詳細にログとして出力されます。
GAMに対してのKey-Valueの付与は次のようなログで確認できます。
1 |
MESSAGE: Attempting to set key value for slot: XXXXX key: hb_pb value: XX.XX |
このときにログが確認できない、あるいは意図していないslot(=広告枠)またはKey-Valueにが付与されている場合、設定scriptに何か問題ないか確認してみましょう。
googletag.openConsole()
先の「pbjs_debug=true」はPrebid.jsが提供しているデバッグのロガーですが、GAMはGAMで標準で提供しているものがあります。それが「googletag.openConsole()」です。
「Console」パネルで「googletag.openConsole()」と打ってみてください。
するとUIの方に「Show Console」というオーバーレイが表示されるはずです。
これをクリックすると今度はGAMの処理経過のログや、引かれた広告申込情報、その他ログが確認できます。
こちらも「pbjs_debug=true」のときと同じく、次のようなログでKey-Valueの付与具合を確認できます。
1 |
XXXXX にターゲティング属性 hb_pb=XX.XX を設定します |
同じくKey-Valueの付与のログが確認できない、その他意図していない設定が確認された場合は、設定scriptに問題ないか確認しましょう。
ちなみにGAMに対してKey-Valueを付与するには、先に説明した次のAPIの実行順が重要です。
- 「googletag.pubads().disableInitialLoad();」
- 「pbjs.setTargetingForGPTAsync();」
- 「googletag.pubads().refresh();」
これらが正しい順番で設定されているか見てみましょう。
それぞれキューに入れて実行する仕組みになっているので、非同期に処理される関係からブレークポイントを使って実行順を確認するのが確実です。
ブレークポイントの使用方法はこちらなど参照ください。
Key-Valueの付与調査であれば「pbjs_debug=true」でも「googletag.openConsole()」でもどちらでもできます。より詳細にPrebid.jsを見たいなら前者、GAMを見たいなら後者といった使い分けができれば良いと思います。
まとめ
かなりのボリュームになってしまいましたが、以上でGAMとPrebid.jsの説明となります。
今回はGAM、Prebid.js、そしてその両者の連携の概要を掴んでもらうことを目的として書いた記事ですので、それぞれの詳細はいくつかカットしています。
当然GAM、Prebid.jsはここで紹介した以上にもっと複雑な設定ができます。そしてデバッグはより難解になることが多いです。
ただ今回説明した内容を追っていくことで、概ねどこが原因か、あたりはつけやすくなるはずです。
そして改めて、Prebid.jsの導入・運用にあたってはGAMとPrebid.jsの知識が必要だということも分かっていただけたと思います。私も導入にあたっては、当時の広告運用担当と二人三脚でやっていましたが、今振り返ってみても、とてもじゃないですが一人ではできなかったと感じています。
個人的にはよくGAMにつまづいていたので、GAM初心者の方はなるべく早く経験者に聞ける環境を作った方が良いかもしれません。(「オーダーの有効化」であったり、クリエイティブのサイズ指定の漏れ、開始時期の設定など、本当に惑わされることが多いです。)
Prebid.jsは広告運用担当者と開発担当者の連携が成功への鍵ですので、本記事がこれからはじめようと考えている方、あるいは深く学ぼうとしている方への足掛かりになったら幸いです。
なおKey-Valueで連携している関係から、GAMの広告申込情報については事前に大量に作る必要があると分かったかと思いますが、これを手作業でやると大変な工数がかかります。
作成にあたってもしAPI活用を検討されている方は、以前にGAM APIを触ってみた記事を書きましたので、よろしければこちらもご覧ください。

そして当然DevToolsも高度に使えるようになるとデバッグも楽です。
下記以前に投稿したDevToolsにまつわるテクニック、その他調査方法ですので、よろしければこちらも参照ください。


明日は、mizkichさんによる「BigQuery独自エラーのトラブルシュート集」です。
引き続き、GMOアドマーケティング Advent Calendar 2020 をお楽しみください!
■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~
https://www.gmo-ap.jp/engineer/
■noteページ ~ブログや採用、イベント情報を公開中!~
https://note.gmo-ap.jp/