ある朝、AdMobのメディエーションレポートを開いて、ひとつのアドネットワークのフィル率が前週より落ちているのに気づきました。eCPM自体は悪くないのに、配信機会の取りこぼしが増えている。在庫を売り切れていない時間帯がある、ということです。そこで以前から保留にしていた「ウォーターフォールに新しいネットワークを2社足す」という宿題に、ようやく手をつけることにしました。
アーティスト・個人開発者の廣川政樹です。2014年から壁紙や癒し系のアプリを個人で作り続けていて、累計のダウンロードは5,000万を超えました。広告まわりはここ数年いちばん手を入れている領域で、今回はPangleとMintegralをAdMobのメディエーションに追加し、2週間ほど回してみた実データの話を残しておきます。派手な結論はありません。ただ、追加を検討している方が「自分のアプリだとどうだろう」と当たりをつけられる程度には、正直な数字を共有します。
なぜ2社を追加したのか
私のアプリは表示単価が地域でかなり振れます。日本のユーザーが多い時間帯はeCPMが高く保てるのですが、海外比率が上がる時間帯になると、既存ネットワークだけではフィル率が落ちて、リクエストに対して広告が返ってこない瞬間が出ます。ここを埋める候補として、海外在庫に強いとされるPangleと、ゲーム系の出稿が厚いMintegralを選びました。
選定の理由はシンプルで、どちらもAdMobのオープンビディングおよびウォーターフォール双方に対応していて、追加の手間が比較的小さいからです。1997年、16歳で独学のプログラミングからインターネットに触れたときから、私は「とりあえず一度つないで実データを見る」という確かめ方が好きでした。広告ネットワークの良し悪しも、評判より自分のアプリの数字で判断したいと考えています。
設定でやったこと
追加そのものは難しくありませんが、つまずきやすい点が3つありました。順に書きます。
まず、AdMobの管理画面でそれぞれのネットワークを「メディエーショングループ」に加えます。このとき、ビディング対応のものはビディング枠に、ウォーターフォール配信のものは手動eCPMの行として登録します。私は最初、両方をビディングに寄せてしまい、Mintegral側のウォーターフォール在庫を取りこぼしました。
次に、各ネットワークの管理画面側でアプリIDと広告ユニットIDを発行し、AdMobのマッピングに貼り付けます。ここはコピー&ペーストの作業ですが、テスト環境と本番の取り違えが起きやすいので、私は次のようにメモを一行残してから作業します。
# mediation_mapping_memo.txt
app: WallpaperApp-iOS unit: interstitial_main
pangle: placement=YOUR_PANGLE_PLACEMENT_ID mode=bidding
mintegral: unit=YOUR_MINTEGRAL_UNIT_ID mode=waterfall floor=manual
# 確認: テストID(t_xxx)が本番に紛れていないか push 前に grep する
最後に、SDKを追加します。React Nativeベースのアプリでは、各メディエーションアダプタを入れたうえでネイティブの依存解決を確認します。iOSではSKAdNetworkの識別子をInfo.plistに追記する必要があり、これを忘れるとアトリビューションが欠けて、結果的にeCPMが本来より低く見えます。各ネットワークが公開している識別子の一覧を、漏れなく反映してください。
ビディングとウォーターフォールを混在させるときの整理
ここでいちばん誤解されやすいのが、ビディングとウォーターフォールは「どちらか一方」ではなく「同じグループの中で共存する」という点です。AdMobのメディエーションは、まずビディング対応ネットワーク(およびAdMobネットワーク自身)でリアルタイムのオークションを走らせ、そこで得られた最高入札額を、ウォーターフォールに並んだ手動eCPMの各行と比較します。勝った側が配信されます。
つまりウォーターフォールの各行に設定する「手動eCPM」は、単なる期待値ではなく、ビディングの結果と競わせるための「floor(下限単価)」として機能します。ここを高くしすぎると、その行はほとんど呼ばれずフィルに貢献しません。低くしすぎると、本来もっと高く売れた在庫を安値で手放します。私は初期値を、そのネットワークの過去実績eCPMの中央値あたりに置き、1週間ごとに上下させて様子を見る運用にしています。
私が最終的に落ち着いた配置は、おおよそ次のとおりです。ネットワークの対応方式と、私の壁紙アプリでの役割を整理しておきます。
| ネットワーク | 対応方式 | 私の配置 | 手動eCPMフロアの置き方 |
| AdMob Network | ビディング相当 | 常時オークション参加 | 設定不要(自動) |
| Pangle | ビディング + ウォーターフォール | ビディング主体 | ウォーターフォール行は低めのフロアで補完 |
| Mintegral | ビディング + ウォーターフォール | ウォーターフォール主体・比率を絞る | 実績中央値の少し上に置き、勝てる時だけ拾う |
ポイントは、同じネットワークをビディングとウォーターフォールの両方に登録してよいことです。ビディングで負けても、ウォーターフォールの行でもう一度チャンスがあります。私はPangleをこの二段構えにしてから、海外時間帯のフィルがさらに安定しました。
フィル率とeCPMのどちらを優先するかを式で捉える
「フィル率が上がったのにeCPMが横ばいなら、収益は本当に増えているのか」という疑問は当然です。ここは感覚ではなく、簡単な式に分解すると迷いが減ります。私はインタースティシャルの実効収益を、次のように捉えています。
実効収益 ≒ 広告リクエスト数 × フィル率 × (表示率) × eCPM ÷ 1000
表示率(フィルした広告が実際に表示された割合)を一定とみなせば、収益はフィル率とeCPMの掛け算で効いてきます。だからこそ、eCPMが横ばいでもフィル率が上がれば収益は増えます。私のケースを、丸めた相対値で並べてみます。
| 指標 | 追加前の2週間 | 追加後の2週間 | 差分 |
| フィル率 | 約92% | 約97% | +5ポイント |
| 平均eCPM(相対値) | 1.00 | 1.01 | ほぼ横ばい |
| フィルした表示回数(相対) | 0.92 | 0.97 | +約5.4% |
| 実効収益(相対) | 0.92 | 0.98 | +約6.5% |
表示回数の母数が大きいほど、この5ポイントは効いてきます。私の場合、月の総収益で見ると数パーセントの底上げになりました。ここから導ける判断軸は明快です。フィル率が95%を割っているなら、まずネットワークを足してフィルの穴を埋めるほうが費用対効果が高い。フィル率がすでに98%以上で頭打ちなら、次はeCPMを引き上げる施策(floorの調整、広告フォーマットの見直し、ATT許諾率の改善)に軸足を移す。フィルとeCPMを同じ土俵で語らず、今どちらのボトルネックに立っているかを先に決めるのが、遠回りしないコツだと感じています。
2週間の実データ
ここからが本題です。インタースティシャル広告について、追加前の2週間と追加後の2週間を比べた、ざっくりした傾向を共有します。金額は私のアプリの相対値であり、ジャンルやユーザー地域で大きく変わる前提で読んでください。
追加で見えた変化は、おおよそ次のとおりでした。
- 全体のフィル率: 約92%から約97%へ。取りこぼしていた時間帯が確実に埋まりました
- 全体の平均eCPM: ほぼ横ばい(わずかにプラス)。単価が劇的に上がったわけではありません
- Pangle: 海外比率の高い時間帯でフィルに貢献。eCPMは中程度で、安定して在庫を返してくれる印象
- Mintegral: フィルは堅いものの、私の壁紙アプリではeCPMが既存ネットワークをわずかに下回る時間帯が多めでした
つまり、収益が跳ね上がったのではなく、「これまで広告が出ていなかった隙間が埋まった」というのが正確な表現です。フィル率5ポイントの改善は、表示回数の母数が大きいアプリほど効いてきます。私の場合、月の総収益で見ると数パーセントの底上げにつながりました。劇的ではありませんが、設定変更だけで得られる改善としては十分に意味があります。
ぶつかった壁
ひとつは、追加直後の数日はデータを信用しないほうがよい、という点です。新しいネットワークは学習期間があり、最初の2〜3日はeCPMが本来の実力より低く出ることがあります。私は焦って初日の数字で判断しかけましたが、1週間ならして見るとPangleの評価は上がりました。短期の数字で切り捨てると、伸びしろを捨てることになります。
もうひとつは、ATT(アプリのトラッキング透明性)の許諾率の影響です。許諾を得られていないユーザーが多い環境では、どのネットワークもパーソナライズ広告を出せず、eCPMが下がります。これは追加したネットワークの優劣ではなく、許諾率という前提条件の問題です。ネットワーク比較をするなら、ATTの許諾率がある程度安定してから評価するのが公平だと感じました。
地域と時間帯でメディエーショングループを分ける手順
ひとつのグループでまとめて評価したあと、私は地域でグループを切り直しました。海外比率が上がる時間帯にPangleを厚く配信し、日本ユーザーが多い時間帯は既存ネットワークとAdMobのビディングに任せる、という切り分けです。手順を残しておきます。
- AdMobの「メディエーション」から新しいメディエーショングループを作成し、対象の広告ユニットを割り当てます。既存グループを複製すると、マッピングを引き継げて速いです。
- グループの「ターゲティング」で地域(国・地域)を指定します。私は「海外向け」と「国内向け」の2グループに割りました。国内向けはeCPMの高いネットワークを上位に、海外向けはPangleのフロアを下げてフィル優先に置きます。
- 両グループが同じ広告ユニットを参照している場合、AdMobは端末の地域に応じて自動的にどちらのグループを使うか判定します。重複配信にはなりません。
- 変更後は最低1週間、できれば2週間は触らずに寝かせます。学習期間中に何度もフロアをいじると、どの変更が効いたのか切り分けられなくなります。
- 週次でグループ別のeCPM・フィル率・表示回数を比べ、地域ごとにネットワークの並び順とフロアを微調整します。
この分割で、海外時間帯のフィルの穴が「埋まる」から「先に取りにいく」に変わりました。同じネットワークでも、置く場所を変えるだけで役割が変わるのが面白いところです。
日次のeCPMとフィル率を自分で見張る
管理画面を毎朝開くのは続きません。私はAdMobのReporting APIで、前日のネットワーク別eCPMとフィル率を取得し、閾値を割ったらSlackに通知する仕組みを回しています。骨組みだけ載せます。認証は事前にサービスアカウントで済ませてある前提です。
// admob_daily_watch.mjs — 前日のネットワーク別 eCPM / フィル率を取得して閾値監視
import { google } from 'googleapis';
const auth = new google.auth.GoogleAuth({
keyFile: 'YOUR_SERVICE_ACCOUNT_JSON',
scopes: ['https://www.googleapis.com/auth/admob.report'],
});
const admob = google.admob({ version: 'v1', auth });
const PUBLISHER_ID = 'pub-YOUR_PUBLISHER_ID';
const FILL_ALERT = 0.95; // フィル率がこれを割ったら通知
function yesterday() {
const d = new Date(Date.now() - 24 * 60 * 60 * 1000);
return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() };
}
const res = await admob.accounts.mediationReport.generate({
parent: `accounts/${PUBLISHER_ID}`,
requestBody: {
reportSpec: {
dateRange: { startDate: yesterday(), endDate: yesterday() },
dimensions: ['AD_SOURCE'],
metrics: ['ESTIMATED_EARNINGS', 'IMPRESSIONS', 'MATCH_RATE', 'IMPRESSION_RPM'],
},
},
});
for (const row of res.data) {
const r = row.row;
if (!r) continue;
const source = r.dimensionValues.AD_SOURCE?.displayLabel ?? 'unknown';
const matchRate = Number(r.metricValues.MATCH_RATE?.doubleValue ?? 0);
const rpm = Number(r.metricValues.IMPRESSION_RPM?.microsValue ?? 0) / 1_000_000;
const line = `${source}: fill=${(matchRate * 100).toFixed(1)}% eCPM≈${rpm.toFixed(2)}`;
if (matchRate > 0 && matchRate < FILL_ALERT) {
await notifySlack(`⚠️ フィル率低下 ${line}`); // 実装は各自の webhook で
}
console.log(line);
}
MATCH_RATE がフィル率、IMPRESSION_RPM が実質のeCPMに相当します。ネットワーク別に前日値を並べておくと、どのネットワークが急に沈んだかを朝いちばんで気づけます。冒頭のエピソードのように「気づいたら1週間取りこぼしていた」を防ぐ、いちばん地味で効く一手です。
追加前に潰しておく落とし穴
同じつまずきを繰り返さないよう、私が毎回チェックしている点を残します。
- SKAdNetworkの識別子をInfo.plistに追記したか。忘れるとアトリビューションが欠け、eCPMが本来より低く見えて誤判断します。
- テストID(
t_ などの接頭辞)が本番マッピングに紛れていないか。push前にgrepで機械的に確認します。
- ウォーターフォールの手動eCPMフロアが高すぎないか。その行が一度も勝っていないなら、フロアを下げるか行を外します。
- 追加直後の2〜3日の数字で結論を出していないか。学習期間を織り込み、最低1週間ならして評価します。
- ATTの許諾率が直近で大きく動いていないか。前提が動いているとネットワーク比較が公平になりません。
今の判断軸
2週間回してみて、自分の中で固まった見方は「フィル率の穴埋め」と「eCPMの底上げ」は別の目的として分けて考える、というものです。Pangleは前者にはっきり効きました。Mintegralは私の壁紙アプリのジャンルでは後者への寄与が小さく、配信比率を絞り気味に運用しています。同じ2社でも、ゲームやユーティリティ系のアプリでは結果が逆になる可能性は十分にあります。
ネットワークの評判は参考になりますが、最終的には自分のアプリの地域構成・ジャンル・表示頻度で数字が決まります。だからこそ、保留にせず一度つないで2週間ぶんのデータを取る、というやり方を私は続けています。
これから取り組むこと
次は、時間帯と地域でメディエーショングループをさらに細かく分け、Pangleの配信比率を海外比率が上がる時間帯に寄せられないかを試すつもりです。地域でグループを切ると、それぞれのネットワークの得意な場面がもっとはっきり見えてくるはずだと考えています。
同じように「新しいネットワークを足すかどうか」で迷っている方は、まず1つだけ、フィル率に穴のあるアプリへ2週間つないでみてください。判断材料は評判ではなく、自分の手元の数字から得るのがいちばん確かです。お読みいただきありがとうございました。