iOS と Android で動かしている壁紙アプリ 2 本に、AdMob メディエーショングループが今 50 を超えています。BW iOS で 28、BW Android で 14、UKI iOS で 16、UKI Android で 6。1 アプリで 1 つだったメディエーションが、ATT (App Tracking Transparency) の ON/OFF と地域分割で増えていった結果です。
朝いちばんに AdMob のレポートを開いてフロア値(eCPM 下限値)を手でいじる時間が、じわじわ伸びておりました。ある朝、コーヒーが冷めるまでずっと同じ画面をスクロールしていて、これは作業の量ではなく手順が決まっていないせいだと気づきました。そこでひと月かけて、エージェントに任せられる作業と、自分が握り続けるべき判断を切り分けてみたのです。
「個人開発で AdMob メディエーションを 10 グループ以上抱えていて、調整の手作業が無視できない量になってきた」「エージェントに任せたいが、収益に直結するので不安」あたりで悩んでいる方に向けて、再現できる手順として書き残します。
なぜグループ数がここまで増えたのか
エージェントの話に入る前に、1 アプリ 50+ グループに到達した理由を整理しておきます。これを把握しないと、自動化の対象範囲が決まりません。
AdMob のメディエーションは、最近の運用ベストプラクティスで「ATT ON / OFF × 主要国 × フォーマット (INT/BNR/RWD/RWI/AOA)」の組み合わせでグループを分けるのが標準です。私の運用ですと、たとえば BW iOS の INT (インタースティシャル) は次のような割り方になっています。
- BW-INT-iOS-JP-ATT-ON / OFF
- BW-INT-iOS-TW-ATT-ON / OFF
- BW-INT-iOS-US-ATT-ON / OFF
- BW-INT-iOS-IT-ATT-ON / OFF
- BW-INT-iOS-DE-ATT-ON / OFF
- BW-INT-iOS-HK-ATT-ON / OFF
- BW-INT-iOS-ROW-ATT-ON / OFF
7 地域 × ATT 2 値 = 14 グループ。これに BNR・RWD・RWI を加えると 1 プラットフォームで 30 以上、両 OS で 60 グループ前後になります。実勢 eCPM はグループごとに $1 から $34 まで散らばっていて、それぞれにフロア値の最適点があります。
ここで「フロア値」とは、Bidding/Waterfall を含む全ネットワークに対する eCPM の最低ラインのことです。フロア値を高くすると単価は上がりますがマッチ率(広告が表示される割合)が下がり、低くするとその逆になります。私の運用基準は 実勢 eCPM × 50〜60% を目安にする、フロア/eCPM 比が 65% を超えたら見直す、というものです。
任せていい作業 — エージェントに切り出した 4 工程
ひと月ほど試行錯誤して、エージェントに任せて支障がなかった作業は次の 4 つでした。
最初の一つはマッチ率モニタリングです。AdMob のレポート画面を 30 日期間で開いて、グループごとのインプレッション・マッチ率・推定収益を集計する作業になります。エージェントには次のような指示を出します。
AdMob のレポートで以下を実行してください:
1. 期間: 過去 30 日
2. ディメンション: アプリ + メディエーショングループ
3. 指標: 広告リクエスト、インプレッション、マッチ率、推定収益
4. フィルタ: matchrate < 80% のグループのみ抽出
5. 出力: グループ名 / 現在のフロア / 実勢 eCPM / フロア-eCPM 比 /
広告リクエスト数 / 推奨アクションエージェントは API もしくは CSV エクスポート経由でデータを取り、表に整形して返します。私はその表を眺めて「JP は維持、ROW は調整」の判断を入れるだけです。集計の手作業が 30 分から 3 分になりました。
二つ目はフロア-eCPM 比の検算です。単純な計算ですが、人間がやるとミスが入りやすい部分でもあります。
def evaluate_floor(group_name, current_floor, ecpm_30d, matchrate):
"""フロアと実勢 eCPM の関係を評価して、推奨アクションを返す。"""
ratio = current_floor / ecpm_30d
if matchrate < 0.80:
if ratio > 0.65:
return f"{group_name}: ratio={ratio:.2%} - 下げる候補(matchrate {matchrate:.0%})"
else:
return f"{group_name}: ratio={ratio:.2%} - 需要不足の可能性(フロア無関係)"
if ratio > 0.65:
return f"{group_name}: ratio={ratio:.2%} - 比率高めだが matchrate OK、維持"
return f"{group_name}: 健全"
# 期待される出力:
# BW-INT-AND-JP: 比率高めだが matchrate OK、維持
# BW-INT-AND-DE: ratio=88.96% - 下げる候補(matchrate 56%)この関数には後から見つけた穴が二つあります。あとの節でまとめて直しますので、いまはこの形のまま読み進めてください。
三つ目は運用記録の更新です。フロア値を変更したら、admob-mediation-unified.md のような運用台帳に「日付 / グループ ID / 変更前 → 後 / 理由」を追記します。これはエージェントに丸投げしております。私は変更内容を口頭で説明するだけで、エージェントが整形して台帳に追記してくれます。後から「なぜ 2026-05-17 に JP のフロアを $15 → $12 に下げたか」を思い出せる状態が、半年後の自分にとっての資産になります。
四つ目はフロア値の「半分ルール」適用です。AppLovin MAX を Waterfall に追加したときに、Unity Ads のフロア値の半分に AppLovin の手動 eCPM を設定する、という運用ルールになります。Unity が $8.50 なら AppLovin は $4.25、Unity が $5.00 なら $2.50。20 グループ分を手で計算するとミスが出ますので、エージェントに次のように頼みます。
以下の表の Unity フロア列を読み、半分ルールに従って AppLovinMax の
waterfall フロアを計算してください。出力は AdMob の編集画面に貼り付ける
形式(数値だけ)。BNR グループは Unity 値を無視して固定 $0.15 で出力。
| グループ ID | Unity フロア (waterfall) |
| BW-INT-AND-JP (8292611016) | $8.50 |
| BW-INT-AND-KO (5982272500) | $5.00 |
| ... |出力はそのまま AdMob の編集画面に貼り付けます。10 グループ分が 1 分で終わる作業ですが、手で電卓を叩いていると 1 件は間違えるのです。
掲載していた判定コードに残っていた穴
この記事を書いたあとで evaluate_floor() を読み返していて、手が止まりました。マッチ率を点推定のまま閾値と比べていたのです。
マッチ率は「広告リクエストのうち何回埋まったか」という比率ですから、母数が小さいほど数字は暴れます。30 日で 172 リクエストしかない小さな地域のグループと、2,000 リクエストあるグループを、同じ 80% の線で切っていたことになります。
どれくらい違うのかを、Wilson 法の 95% 信頼区間で出してみました。観測マッチ率が 75% のとき、リクエスト数ごとの区間は次のようになります。
| 広告リクエスト数 | 観測マッチ率 | 95% 信頼区間 | 区間の半幅 | 「80% 未満」と言えるか |
|---|---|---|---|---|
| 30 | 75.0% | 55.6% – 85.8% | 15.1pt | 言えません |
| 100 | 75.0% | 65.7% – 82.5% | 8.4pt | 言えません |
| 200 | 75.0% | 68.6% – 80.5% | 6.0pt | 言えません |
| 300 | 75.0% | 69.8% – 79.6% | 4.9pt | 言えます |
| 1,000 | 75.0% | 72.2% – 77.6% | 2.7pt | 言えます |
| 5,000 | 75.0% | 73.8% – 76.2% | 1.2pt | 言えます |
観測 75% で「80% を下回っている」と 95% の確からしさで言い切るには、230 リクエストが要ります。観測が 78% と目標に近い場合はもっと厳しく、1,498 リクエストまで待たないと区間の上限が 80% を割りません。観測 60% まで落ちていれば 14 リクエストで足ります——差が大きいほど少ない母数で判断できる、という当たり前の話が、そのまま運用の待ち時間の差になります。
もう一つの穴は、ecpm_30d がゼロや欠損のときに割り算で落ちることでした。配信が始まったばかりの BNR グループでは実際に起こります。
直した版がこちらです。
from math import sqrt
Z95 = 1.96
def wilson(matched, requested, z=Z95):
"""マッチ率の信頼区間(下限, 上限)を返す。"""
if requested <= 0:
return (0.0, 1.0)
p = matched / requested
d = 1 + z * z / requested
center = (p + z * z / (2 * requested)) / d
margin = z * sqrt(p * (1 - p) / requested + z * z / (4 * requested * requested)) / d
return (center - margin, center + margin)
def evaluate_floor(group, floor, ecpm_30d, matched, requested,
target=0.80, min_requests=200):
if not ecpm_30d:
return f"{group}: eCPM が 0 か欠損 - 判定不能"
if requested < min_requests:
return f"{group}: requests={requested} - 母数不足につき判定保留"
ratio = floor / ecpm_30d
lo, hi = wilson(matched, requested)
if hi < target:
if ratio > 0.65:
return f"{group}: ratio={ratio:.0%} / CI={lo:.0%}-{hi:.0%} - 下げる候補"
return f"{group}: ratio={ratio:.0%} / CI={lo:.0%}-{hi:.0%} - 需要不足の可能性"
if lo >= target:
if ratio > 0.65:
return f"{group}: ratio={ratio:.0%} - 比率高めだが matchrate は目標以上、維持"
return f"{group}: 健全"
return f"{group}: CI={lo:.0%}-{hi:.0%} が 80% をまたぐ - 判定保留"手元で 5 件のグループを通した出力です。
BW-INT-AND-DE: ratio=178% / CI=54%-58% - 下げる候補
BW-INT-AND-JP: ratio=98% / CI=43%-47% - 下げる候補
UKI-RWD-iOS-HK-ATT-OFF: requests=172 - 母数不足につき判定保留
UKI-BNR-iOS-IT-ATT-ON: eCPM が 0 か欠損 - 判定不能
BW-INT-AND-TW: CI=71%-81% が 80% をまたぐ - 判定保留注目していただきたいのは最後の 2 行です。UKI-RWD-iOS-HK は 172 リクエストしかないので保留に落ちました。BW-INT-AND-TW は 280 リクエスト中 214 マッチで観測 76%、旧コードなら迷わず「下げる候補」に並んだはずですが、区間は 71%–81% で 80% をまたいでいます。この状態でフロアを下げると、翌月マッチ率が戻ったときに「下げたから戻った」と読み違えてしまうかもしれません。
閾値を割ったかどうかではなく、割ったと言い切れるかどうかで動く。 この線引きを入れてから、月次で触るグループの数は減りました。触らないという判断が出力に現れるようになったのが、いちばんの変化だと感じています。
握り続ける判断 — エージェントに渡さない 4 領域
一方で、私が手放さずに人間の判断として握り続ける領域もあります。「収益に直結する」「データだけでは判断しきれない」「事業ロジックが入る」のいずれかに該当するものです。
最初の一つはフロア値の絶対値設定です。「$15 を $10.50 に下げる」のような具体的な数字は、エージェントが提案してきても最終承認は私が行います。理由は単純で、AdMob のフロア値は実勢 eCPM の動きだけでなく、地域の広告需要シーズン(年末商戦・新生活シーズン)や、特定ネットワーク(Meta, AdMob Network)の調子の波と連動しているからです。データだけを見ていると、見落とす要因が多すぎるのです。
二つ目はネットワーク全停止・全解除の判断です。たとえば 2026-05-26 に AppLovin の Bidding と Waterfall を全アプリの INT/RWD/RWI で停止しました。理由は CTR 13% × RPC $0.0092 × eCPM $1.21 という異常な広告品質指標と、長期のクラッシュトレンドで AppLovin 導入時期に明確なスパイクパターンが全アプリで観察されたことです。これはデータと一次情報の照合が必要で、エージェントには任せきれません。月収 $730 ほどを捨てる判断は、自分の責任で行うべき種類のものだと思っています。
三つ目は異常値の解釈です。マッチ率が前週比で大きく動いた、特定グループの eCPM が突然 2 倍になった、というシグナルが出てきたとき、その原因が「ネットワーク側の入札ロジック変更」「自分の側のアプリリリースのタイミング」「季節要因」のどれなのかを判別するのは、エージェントには難しいのです。私の場合は Crashlytics・Play Console・App Store Connect・AdMob レポートを横並びに置いて推測しますが、ここは人間の側にしか文脈が揃わないことが多いように思います。
四つ目は広告 SDK の入れ替え判断です。Mintegral を入れる・抜く、InMobi を審査に出す、Meta の優先順位を上げる、といった判断は、収益だけでなくクラッシュリスク・ユーザー体験・SDK サイズ(apk フットプリント)に影響します。エージェントに「Meta が AdMob Network より平均 eCPM が高い」と教えてもらっても、私はそれを根拠に Meta を昇格させたりはしません。SDK の挙動の癖(Meta の Code 1002 too frequently のような頻度キャップ問題など)は、運用者の経験のほうが判断材料として優先されます。
任せ方の具体例 — 月次レビューのループ
毎月 1 回、AdMob メディエーションの全体レビューを行うスケジュールタスクを組んでおります。エージェントには次のフローを回してもらいます。
[Step 1] AdMob レポートからデータ取得
- 期間: 過去 30 日
- 全 50+ グループの広告リクエスト / インプレッション / マッチ率 /
推定収益 / 実勢 eCPM
- 結果を構造化データ(JSON / CSV)で保持
[Step 2] フロア-eCPM 比の機械評価
- 全グループに対して evaluate_floor() を実行
- 「下げる候補」「上げる候補」「維持」「需要不足の可能性」
「母数不足につき判定保留」に分類
[Step 3] 前月との差分計算
- 先月の運用台帳と比較
- eCPM が ±20% を超えて動いたグループをハイライト
[Step 4] レポート生成
- 上位 5 件の収益寄与グループ
- 下位 5 件のマッチ率(区間つき)
- 「人間の判断を要する」分類の一覧
- 機械的に適用可能な変更案出力されたレポートを朝コーヒーを飲みながら読み、「適用可能な変更案」のうち承認したものだけをエージェントに「実行」と指示します。エージェントは AdMob の画面操作(手動 GUI が必要なものはブラウザツール経由)で変更を当て、admob-mediation-unified.md に追記して終わります。
この月次レビューは、エージェントを入れる前は 1 回 3〜4 時間かかっておりました。いまは 30 分以内で終わります。浮いた 3 時間は、別のアプリ側のコード保守や、レビュー返信のような「エージェントに任せられない」作業に回せる時間になりました。
任せきって失敗した例
エージェントに任せて失敗した例も書いておきます。同じ罠を踏む方がいらっしゃるかもしれませんので。
フロア値を一時的に OFF にする提案を承認してしまったケースです。あるグループのマッチ率が低下したのを見て、エージェントが「フロアを一時 OFF にしてマッチ率を回復させる」と提案してきました。私が承認したところ、Bidding を含む全ネットワークの最低 eCPM がなくなり、eCPM 全体が崩れました。Waterfall の手動 eCPM はフロアの代替にはならない、というのは AdMob の仕様上明らかなのですが、エージェントの提案を鵜呑みにすると気づきにくいのです。
これ以後、私は次のルールを feedback_admob_ecpm_floor_warning.md に書き込んで、エージェントへの指示テンプレに毎回コピーするようにしました。
[禁止事項]
- INT グループのフロア値を OFF にしてはいけない
- フロアを OFF にすると Bidding 含むメディエーション全体の最低 eCPM が消える
- Waterfall 手動 eCPM はフロアの代替にならないエージェントに任せるときは、「やってほしいこと」だけでなく「絶対にやってほしくないこと」も明示的に渡すのが安全策です。いま思えば、この禁止事項リストがないまま承認ボタンを押していたのが、そもそもの間違いでした。
実例で見るチューニング履歴
実際に直近で動かしたチューニングを並べておきます。各行は「データ観察 → 判断 → 実行」の流れで、エージェントの関与度合いが分かるようにラベルを付けています。
- 2026-05-17 (Android BW-INT): 30 日 eCPM が JP $15.23、KO $8.64、TW $8.87、DE $5.62 と判明。matchrate は JP 45% / KO 47% / TW 67% / DE 56% で全部 80% 未満。エージェントが「フロアが高すぎる候補」として全部リストアップ → 私が承認 → フロアを JP $15→$12、KO $10→$7、TW $10→$8、DE $10→$5 に変更
- 2026-05-24 (BW/UKI Android 全 20 グループ): AppLovin MAX を Unity の半分にする「半分ルール」を一括適用。エージェントが計算 → 結果を出力 → 私が AdMob 編集画面で 20 グループ分の数値を貼り付け
- 2026-05-26 (全 iOS/Android AppLovin INT/RWD/RWI 全停止): クラッシュ証拠と CTR 異常値を見て判断、AdMob 側で Pause。エージェントには
applovin-stop-decision-2026-05-26.mdの整理を任せましたが、停止操作そのものは手動で実施
最後の AppLovin 全停止のような大きな判断は、「エージェントに整理を頼んで、自分が手動で実行する」の形が向いています。データ集計と論点整理は機械に任せ、ボタンを押す瞬間は自分の手で。
なお 5 月 17 日の一括変更は、いまの判定コードなら同じ結論にはなりません。JP は 45% でリクエスト数も十分でしたので「下げる候補」のまま残りますが、母数の小さい地域は保留に落ちます。当時の私は、数字が並んでいることと、数字が確かなことを区別できておりませんでした。
個人開発で「半分エージェント化」を始めるなら
これから AdMob メディエーション運用にエージェントを入れる方向けに、最初の 1 週間でやる順序を書いておきます。
- 既存のメディエーショングループを一覧化した運用台帳(
admob-mediation-unified.md等)を 1 ファイルに集約すること - フロア-eCPM 比の評価関数を Python で書き、ローカルで動かして手元のデータで検算すること
- 評価関数には最初から広告リクエスト数の下限(目安 200〜300)を入れておくこと
- マッチ率モニタリングの集計プロンプトを 1 つ完成させ、月次タスクとして組むこと
- 「禁止事項」リストを書き出して、エージェントへの指示テンプレに必ず含めること
- 最初のひと月は、変更案を全部「提案だけ・実行は手動」モードで運用すること
- ひと月の運用が破綻なく回ったら、明らかに低リスクな作業(運用台帳への追記、半分ルールの計算など)から自動実行に格上げすること
個人で AdMob を回してきた経験で言いますと、収益化のチューニングは「速さ」より「再現性」が大事です。今月たまたま eCPM が上がっても、来月の動きを再現できないと意味がないのです。エージェントを入れる目的は「自分の判断ロジックを文書化して、誰が回しても同じ結果が出る形にする」ことで、その副作用として作業時間が短くなる、というのが正しい順序なのだと思います。
浮世絵壁紙のアプリで古い紙の写真を一枚ずつ直していると、直す前に必ず「どこまで直すか」を決めてから手をつけます。決めずに始めると、気づいたときには元の紙にはなかったものまで足しています。メディエーションの運用も同じで、図面(運用台帳と判定基準)が先にあって、エージェントの判断はその図面の中だけで動く——この順序だけは崩さないようにしております。
まずは手元の評価関数に requests の列を足して、母数不足のグループがいくつ混ざっているかを数えるところから始めていただければ幸いです。私もそこからやり直しました。区間の話までお付き合いいただき、ありがとうございました。