個人開発でAdMobのアプリを運用していた頃、収益レポートを毎朝コーヒー片手に眺めるのが日課でした。
ある日、ゲームオーバー画面に出すインタースティシャル広告の位置を数十ピクセル動かしただけで、翌週のARPUが2割近く上がったことがあります。コードのロジックは一行も変えていません。変えたのは、広告とユーザーの視線が出会う場所だけでした。
このとき強く感じたのは、AdMobの収益は「広告ネットワークが決める数字」ではなく「自分のUI設計が決める数字」だということです。CPMはGoogleが決めますが、ユーザーがいつ・どこで広告に出会うかは、私たち開発者が設計できます。
ここでは、私自身がAdMobアプリの運用で積み上げてきた手応えと失敗を、Rorkでの実装手順に落とし込みながら共有します。広告フォーマットの選び方、頻度キャップの実装、同意取得が収益に与える影響、そしてFirebaseでの検証サイクルまで、コード付きで進めます。
収益を分解すると、自分が動かせる変数が見えてくる
AdMobの収益は、次のかけ算で決まります。
収益 = インプレッション数 × CTR(クリック率) × CPM(1,000表示あたりの単価)
多くの開発者はCPMを上げようとしますが、CPMは広告主の入札と広告ネットワークが決めるため、開発者側から直接は触れません。私たちが設計で動かせるのは、残りの2つです。
ひとつはインプレッション数 。1セッションの中で広告が何回表示されるか。もうひとつはCTR 。表示された広告のうち、どれだけ自然にタップされるか。
この2つはどちらもUI設計の領域です。広告をどこに置き、どのタイミングで出すか。その判断が、そのまま収益の差になって返ってきます。
改善前後で何が変わったか
個人開発のカジュアルゲームで、UIだけを見直したときの数字を並べてみます。
改善前は、日次アクティブユーザー(DAU)5,000、セッション長3分、セッションあたりインプレッション1.2回、CTR 3%、CPM 50円。日次収益はおよそ900円でした。
改善後は、DAUは5,000のまま、セッション長は3.5分に伸び(広告が邪魔をせず長く遊んでもらえた結果です)、インプレッションは2.0回、CTRは5%、CPMは50円のまま。日次収益はおよそ2,500円になりました。
DAUもCPMも変えていません。それでも収益は2.8倍です。差を生んだのは広告配置の設計だけでした。
広告の「置き場所」には心地よい順番がある
広告が効くかどうかは、ユーザーの心の状態と深く結びついています。私の運用で安定して成果が出たのは、次の順番でした。
最も成果が出る場所:ゲームオーバー画面
ユーザーがゲームオーバー画面を見た瞬間は、いちばん肩の力が抜けています。「次どうしようか」と画面の続きを待っている状態です。ここに全画面のインタースティシャル広告を出すと、CTRは8〜12%まで上がりました。通常のバナーが1〜2%であることを考えると、桁が違います。しかも自然な流れなので、苛立ちにつながりにくいのが実感です。
次に効く場所:一時停止・メニュー画面
ユーザーが自分の意思でゲームを止めた瞬間は、待ち時間に対する心の準備ができています。「再開」ボタンの上に300x250のバナーを置くと、無理のない範囲で表示を稼げました。
避けたい場所:プレイの真っ最中
集中しているところに広告を割り込ませると、体験が台無しになります。私も初期に一度だけ試して、レビュー欄に「広告がうるさい」というコメントが並び、評価が下がった経験があります。短期のインプレッションは増えても、離脱とアンインストールで結局は損をしました。
3つの広告フォーマットを役割で使い分ける
バナー、インタースティシャル、リワードの3つは、それぞれ役割が違います。1つに偏らず、層を重ねるのが私のやり方です。
フォーマット CTR目安 CPM目安 推奨配置 離脱への影響
バナー 1〜2% 30〜70円 上部・下部に固定 低い(許容範囲)
インタースティシャル 8〜12% 100〜200円 ゲーム終了・区切り 中(頻度に注意)
リワード 20〜40% 30〜50円 ユーザーが選んだとき 低い(選択制)
バナーは常時表示でインプレッションの土台を作り、インタースティシャルは区切りの瞬間に高いCTRを取り、リワードはユーザーが自分で選ぶので満足度を下げません。この3層を組み合わせると、収益と体験のバランスが取りやすくなります。
[プレイ中]
================
| ゲーム画面 |
| |
================
| バナー広告 | ← 下部固定・常時表示
================
[ゲームオーバー]
================
| |
| インタースティ | ← 閉じるまで全画面
| シャル広告 |
| |
================
[メニュー]
================
| バナー広告 | ← 上部
================
| 再開 |
| 新規ゲーム |
| 設定 |
| [動画を見て報酬]| ← リワード広告ボタン
================
頻度キャップを入れ忘れると、収益は逆に落ちる
ここが、私がいちばん高い授業料を払って学んだところです。
インタースティシャルは強力なので、つい「区切りごとに毎回出したい」と思ってしまいます。けれども毎回出すと、ユーザーはすぐに疲れてしまい、セッションそのものが短くなります。短いセッションは結局インプレッションを減らすので、欲張った配置がかえって収益を削るのです。
対策は、広告と広告のあいだに最低限のクールダウンを設けることでした。最後に全画面広告を見せた時刻を覚えておき、一定時間が経つまでは出さない、というシンプルな仕組みです。
import Foundation
import GoogleMobileAds
final class InterstitialManager {
static let shared = InterstitialManager ()
private var interstitial: GADInterstitialAd ?
private var lastShownAt: Date ?
private let cooldown: TimeInterval = 90 // 直近の表示から最低90秒空ける
private var gamesSinceLastAd = 0
private let minGamesBetweenAds = 2 // 2ゲームに1回まで
func canPresent () -> Bool {
gamesSinceLastAd += 1
guard gamesSinceLastAd >= minGamesBetweenAds else { return false }
if let last = lastShownAt, Date (). timeIntervalSince (last) < cooldown {
return false
}
return interstitial != nil
}
func present ( from root: UIViewController) {
guard canPresent (), let ad = interstitial else { return }
ad. present ( fromRootViewController : root)
lastShownAt = Date ()
gamesSinceLastAd = 0
loadNext () // 表示直後に次をプリロード
}
}
「時間」と「ゲーム回数」の両方で縛るのがポイントです。短時間に何度もゲームオーバーになるユーザーにも、ゆっくり遊ぶユーザーにも、過剰にならない頻度に落ち着きます。私の場合、この2軸キャップを入れてからセッション長が回復し、月次のARPUがむしろ上向きました。広告を減らして収益が上がる、という一見逆説的な結果は、頻度キャップを軽視していると見落としがちです。
同意取得(ATT/UMP)は、UIでありながら収益の根幹
技術記事ではあまり語られませんが、広告配置と同じくらい収益を左右するのが、同意取得のUIです。
iOSではApp Tracking Transparency(ATT)の許諾、そしてAdMobの同意管理プラットフォーム(UMP)でのGDPR/プライバシー同意があります。ここで「許可しない」が選ばれるほど、パーソナライズ広告が配信できず、eCPMが下がります。つまり、同意ダイアログをどう見せるかが、そのまま単価に効いてくるのです。
私が効果を感じたのは、システムの許諾ダイアログをいきなり出すのではなく、その前にひと呼吸置く「事前説明(プライミング)画面」を挟むやり方でした。「広告の表示を続けるために、関連性の高い広告を出せるようにご協力ください」という趣旨を、アプリの言葉で先に伝えます。納得してもらってからシステムダイアログを出すと、許諾率が目に見えて改善しました。
import AppTrackingTransparency
import UserMessagingPlatform
func requestConsentThenTracking () {
// 1. まずUMP(GDPR等)の同意情報を更新
let params = UMPRequestParameters ()
UMPConsentInformation.sharedInstance. requestConsentInfoUpdate ( with : params) { error in
guard error == nil else { return }
UMPConsentForm. loadAndPresentIfRequired ( from : nil ) { _ in
// 2. 同意フォームの後にATTを要求(iOS 14.5+)
if #available ( iOS 14.5 , * ) {
ATTrackingManager. requestTrackingAuthorization { _ in
// 3. ここで初めてAdMobを初期化
GADMobileAds. sharedInstance (). start ( completionHandler : nil )
}
} else {
GADMobileAds. sharedInstance (). start ( completionHandler : nil )
}
}
}
}
順番が大切です。UMPの同意 → ATTの許諾 → AdMob初期化、の流れを守らないと、同意前に広告SDKが動いてしまい、ポリシー違反や配信不全につながります。同意取得は「面倒な法対応」ではなく、eCPMを守るための収益施策だと捉え直すと、UIの優先順位が変わってきます。
なお、app-ads.txtの設置も忘れがちです。アプリの公式サイトのルートにこのファイルを置き、自分のAdMobパブリッシャーIDを記載しておくと、なりすまし在庫と区別され、入札単価が安定します。設置の手間に対して効果が大きい、地味だけれど効く施策です。
Rorkには「広告前提」で発注する
ここからが、AIアシストの本領です。Rorkでアプリを生成するとき、広告を後付けするのではなく、最初から広告込みのレイアウトとして発注すると、CTRの取りやすい画面になります。
コツは、プロンプトの中で広告配置を明示的に指定することです。
Create an iOS game app called "Block Rush" with:
Game Mechanics:
- Stack falling colorful blocks
- Game over when blocks reach the top
- Score increases by 10 per block placed
- 3 lives per game
Ad Integration (PRIMARY GOAL):
- Bottom banner ad (320x50) always visible during gameplay,
placed below the score, never overlapping the game area
- Fullscreen interstitial on game over,
then show "Retry" and "Menu" buttons after the ad closes
- "Watch Ad + 1 Extra Life" rewarded button on game over,
shown only when remaining lives < 3
Design Requirements:
- Dark theme (black background, white text)
- Score top-left, lives top-right, no overlap with ad areas
- Large tappable buttons (44pt minimum)
- Portrait and landscape support
Analytics Ready:
- Add Firebase event hooks for: game_start, game_over, ad_impression, ad_click
- Leave comments where each event should be logged
Optimize for AdMob revenue while keeping UX smooth.
Rorkはこの指示から、広告領域とゲーム領域が重ならないレイアウトを組んでくれます。生成後はシミュレーターで動かし、次のような点を確認します。下部バナーが固定されているか、ゲーム画面と重なっていないか、ゲームオーバー時に全画面広告が出るか、閉じた後にメニューへ戻れるか、画面の向きを変えても広告位置が崩れないか。
ずれがあれば、自然言語で直してもらえます。
The bottom banner overlaps the game controls.
Move the game area up by 60 pixels so the banner has its own space.
手でレイアウトを書き直すより速く、配置の試行錯誤に集中できるのがRorkの利点です。私は配置案を2〜3パターン生成し、後述のA/Bテストにかける形をよく使います。
計測タグを仕込み、ARPUとARPDAUを取り違えない
生成されたコードには、分析イベントが足りないことがあります。Firebase Analyticsのイベントを、広告の節目に手で足しておきます。
import FirebaseAnalytics
Analytics. logEvent ( "game_over" , parameters : [
"score" : score,
"level" : currentLevel
])
Analytics. logEvent ( "ad_impression" , parameters : [
"ad_type" : "interstitial" ,
"position" : "game_over"
])
ここで多くの人がつまずくのが、ARPUの計算です。私も最初は数字を取り違えました。
たとえばAdMobの過去30日の推定収益が150,000円、DAUが5,000だったとします。このとき「ARPU = 150,000 ÷ 5,000 = 30円」と計算したくなりますが、これは月間の一人あたり収益(月間ARPU)であって、日次の指標ではありません。
日次で見る指標はARPDAU(Average Revenue Per Daily Active User)と呼ばれ、「その日の収益 ÷ その日のDAU」で出します。30日合計15万円なら、1日あたりおよそ5,000円、ARPDAUはおよそ1円です。
指標 計算 この例での値
月間ARPU 月間収益 ÷ DAU 150,000円 ÷ 5,000 = 30円
ARPDAU 日次収益 ÷ DAU 5,000円 ÷ 5,000 = 1円
A/Bテストの判定で見るべきは、日々の変動を素早く捉えられるARPDAUです。月間ARPUは事業全体の規模感を掴むのに使い、施策の良し悪しはARPDAUの推移で判断する。この使い分けをしておくと、テスト結果の解釈がぶれません。
Rork×Firebaseで仮説を検証する
配置を変えたら「良くなったはず」で終わらせず、必ずA/Bテストで確かめます。思い込みで全体展開して収益を落とすのは、いちばんもったいない失敗です。
Firebase A/B TestingとRemote Configを使えば、ユーザーごとに違うレイアウトを配信して比較できます。
// Variant A(現状維持)
{
"banner_position" : "bottom" ,
"interstitial_frequency" : 1.0 ,
"show_reward_button" : true
}
// Variant B(検証)
{
"banner_position" : "top" ,
"interstitial_frequency" : 0.5 ,
"show_reward_button" : true
}
アプリ側では起動時にRemote Configを取得し、配信された値で配置を切り替えます。
let remoteConfig = RemoteConfig. remoteConfig ()
remoteConfig. fetch { _ , _ in
remoteConfig. activate ()
let position = remoteConfig. configValue ( forKey : "banner_position" ). stringValue
position == "top" ? placeBannerAtTop () : placeBannerAtBottom ()
}
測定する指標は次の4つに絞ります。
指標 意味 合格ライン
ARPDAU 1日・1ユーザーあたり収益 BがAより+15%
CTR 広告クリック率 BがAより+20%
セッション長 1セッションの利用時間 BがA以上(短縮させない)
離脱率 アンインストール率 BがA以下(増やさない)
14日ほど回した結果、たとえばARPDAUがA=1.5円・B=1.8円で+20%、CTRはA=4.2%・B=5.1%でBの勝ち、セッション長はほぼ同等、離脱率も同等以下、という形に落ち着けば、Bを全体展開します。ここで大事なのは、収益が上がっても離脱率が悪化していないかを必ず併せて見ることです。片方だけ見て判断すると、短期の数字に騙されます。
小さな改善を月1サイクルで積み上げる
個人開発は時間が限られているので、毎月1つだけ仮説を立てて検証する、という無理のないリズムを私は勧めています。
第1週はFirebaseとAdMobのデータを1時間ほど眺め、今月どこを改善するかを決めて仮説を書きます。第2週はRorkで新しい配置を生成し、Remote Configにバリアントを定義してTestFlightで動作確認します。第3週はテスト対象に配信して監視し、第4週で結果を分析し、勝ったほうを全体展開します。
この回し方で、たとえば3か月続けると次のように積み上がります。1か月目にバナー位置で+20%、2か月目にインタースティシャル頻度の最適化で+15%、3か月目にリワード配置で+12%。複利で効いて、累積ではARPDAUがおよそ1.5倍になります。
一度に大きく跳ねることは稀です。けれど、データに裏打ちされた小さな改善を毎月ひとつ積み重ねていくと、半年・一年で確かな差になって返ってきます。私自身、派手な一手よりも、この地道な積み重ねのほうが結局いちばん効くと感じています。
同じようにAdMobアプリの収益と向き合っている方の、明日の一手のヒントになれば嬉しいです。