深夜に AdMob の管理画面を開いて、国別の eCPM を並べて眺めていた時期があります。同じ壁紙アプリでも、米国のインプレッション単価は日本の2〜4倍。時間帯によっても入札額が波打ち、月末になると広告主の予算消化でふっと数字が持ち上がる。広告収益が月150万円を超えていたピークの頃も、この画面の数字が翌月には半分近くまで沈むことがあり、「収益モデルはひとつに依存してはいけない」という感覚は、このダッシュボードの前で身体に刻まれました。
Rork でアプリを作れるようになった今、企画段階で必ず突き当たるのが「広告か、サブスクか、買い切りか」という分岐です。私自身の運用経験から言えるのは、正解はジャンルと規模によって変わる一方で、明確な不正解のパターンは確実に存在するということ。ここから、3つのモデルを同一条件で試算し直し、ジャンル別の使い分けと Rork での実装の勘所を、実運用の数字とあわせて整理していきます。
3つのモデルの性格 — どこで収益が生まれ、どこで頭打ちになるか
広告(Ad-Based) は、ユーザーが無料で使える代わりに広告表示で収益を得るモデルです。ダウンロード数がそのまま収益基盤になるため、ストアの検索流入が強いジャンルと相性が良い。ただし1ユーザーあたりの価値は低く、体験を損なわない配置設計が生命線になります。
サブスクリプション(Subscription) は、定期課金でユーザーから直接収益を得るモデルです。利益率が高く、積み上がれば月次収益の予測可能性が格段に上がります。代償として「課金し続ける理由」を作り続ける開発体制が前提になり、チャーン(解約率)との長い付き合いが始まります。
買い切り(One-Time Purchase) は、1回だけ支払ってもらうモデルです。実装が最もシンプルで、課金状態の管理も軽い。ただし売上が新規獲得数に完全に依存するため、ダウンロードの伸びが止まると収益も止まります。
ニュースやミニゲーム集は広告向き、毎日使う生産性ツールはサブスク向き、単機能のユーティリティは買い切り向き。これが大枠ですが、後述する試算を見ると「規模のフェーズによって最適解が移動する」ことが分かります。
広告収益(AdMob)の実態 — eCPM・フィルレート・メディエーション
広告収益を左右する指標は eCPM (1,000インプレッションあたりの収益)と フィルレート (広告リクエストに対して実際に配信された比率)です。
日本の eCPM はジャンルにもよりますが、おおよそ $0.50〜$2.00。ゲーム系は高めで、ツール系は低い傾向です。北米・西欧は $2.00〜$8.00、東南アジアは $0.20〜$0.80 という相場感。私のアプリ群でも、ユーザーの地域構成が収益を大きく左右しました。日本向けに最適化したアプリの英語ローカライズを進めたのは、機能追加よりも「同じインプレッションの単価を上げる」ほうが投資対効果が高かったからです。
広告 SDK の選定 — expo-ads-admob はもう使えません
古い解説記事では expo-ads-admob を使った実装が紹介されていますが、このパッケージは Expo SDK から削除済みで、現在は動きません。Rork が生成する Expo プロジェクトで AdMob を使う場合、現行の標準は react-native-google-mobile-ads です。Expo Go では動作しないため、EAS Build での開発ビルドが前提になります。
npx expo install react-native-google-mobile-ads
app.json にはプラグイン設定で AdMob アプリ ID を登録します。
{
"expo" : {
"plugins" : [
[
"react-native-google-mobile-ads" ,
{
"androidAppId" : "ca-app-pub-xxxxxxxx~xxxxxxxx" ,
"iosAppId" : "ca-app-pub-xxxxxxxx~xxxxxxxx"
}
]
]
}
}
リワード広告の最適配置
リワード広告はユーザーが「広告を見る」ことを主体的に選ぶため、完了率が高く eCPM も良好です。ミニゲーム系ならスコア画面に「コイン +100 をもらう代わりに広告を見る」ボタンを置く形が定番。生産性ツールなら「プレミアム機能を1回だけ無料で使うチケット」に応用できます。
現行 API での実装は次のようになります。読み込み完了を待ってから表示する、イベント購読を解除する、という2点を押さえておくと本番で事故が起きにくくなります。
// react-native-google-mobile-ads でのリワード広告実装
import { useEffect, useState } from 'react' ;
import { TouchableOpacity, Text } from 'react-native' ;
import {
RewardedAd,
RewardedAdEventType,
TestIds,
} from 'react-native-google-mobile-ads' ;
// 本番では自分の Ad Unit ID に差し替える
const adUnitId = __DEV__ ? TestIds. REWARDED : 'YOUR_REWARDED_AD_UNIT_ID' ;
const rewarded = RewardedAd. createForAdRequest (adUnitId);
export const RewardAdButton = ({ onReward } : { onReward : ( n : number ) => void }) => {
const [ loaded , setLoaded ] = useState ( false );
useEffect (() => {
const unsubLoaded = rewarded. addAdEventListener (
RewardedAdEventType. LOADED ,
() => setLoaded ( true )
);
const unsubEarned = rewarded. addAdEventListener (
RewardedAdEventType. EARNED_REWARD ,
( reward ) => {
onReward (reward.amount); // 例: コイン +100
}
);
rewarded. load ();
return () => {
unsubLoaded ();
unsubEarned ();
};
}, [onReward]);
return (
< TouchableOpacity
disabled = {!loaded}
onPress = {() => {
rewarded. show ();
setLoaded ( false );
rewarded. load (); // 次回分を先読み
}}
>
< Text >{loaded ? '広告を見てコイン +100' : '読み込み中…' } </ Text >
</ TouchableOpacity >
);
};
インタースティシャル広告の頻度設計 — ポリシー警告から学んだこと
インタースティシャル(全画面広告)は eCPM が高く収益の主体になりやすい一方、配置を誤ると離脱とポリシーリスクの両方を抱えます。私は過去に一度、画面遷移のたびに全画面広告が出かねない実装を見落とし、AdMob からポリシー違反の警告を受けて緊急対応した経験があります。配信制限がかかれば収益はその瞬間からゼロに向かうので、頻度制御はコードで機械的に保証しておくべきです。
目安は「最後の表示から一定時間を空け、かつユーザーが2アクション以上進んでから」。これをクラスひとつで強制します。
// インタースティシャル広告の間隔管理
class AdFrequencyManager {
private lastAdTime = 0 ;
private actionCount = 0 ;
private readonly minIntervalMs = 60_000 ; // 最低60秒
private readonly minActionsBetweenAds = 2 ;
canShowInterstitial () : boolean {
return (
Date. now () - this .lastAdTime > this .minIntervalMs &&
this .actionCount >= this .minActionsBetweenAds
);
}
recordAction () : void {
this .actionCount += 1 ;
}
recordAdShown () : void {
this .lastAdTime = Date. now ();
this .actionCount = 0 ;
}
}
export const adManager = new AdFrequencyManager ();
ピーク時の私の広告構成では、収益の大半をインタースティシャルが占め、バナーは1割程度の補助でした。それでも間隔制御は60秒より短くしませんでした。eCPM の高い広告ほど「出しすぎた瞬間に資産を毀損する」性質があると考えています。
メディエーションは管理画面で組む — クライアント側で入札させない
複数の広告ネットワークを束ねる メディエーション は、eCPM 改善の本命です。私の運用では AdMob を軸に Facebook Audience Network・Unity Ads・AppLovin・Pangle の4ネットワークを束ね、単独運用と比べて eCPM が体感で3〜5割改善しました。
注意したいのは、ネットワーク選択をアプリ側のコードで実装しようとしないことです。かつての私を含め、クライアントで各社の入札額を取得して比較する疑似ウォーターフォールを考えたくなりますが、これはレイテンシとポリシーの両面で筋が悪い。現在の AdMob はメディエーショングループを管理画面で構成し、入札(bidding)はサーバー側で行われます。アプリ側の作業は各ネットワークのアダプタを依存に追加することだけで、広告リクエストのコードは1ネットワークのときと変わりません。
# アダプタの追加例(ネットワークごとに公式アダプタを入れる)
npm install react-native-google-mobile-ads
npm install @react-native-admob/admob-mediation-unity
# 以降、AdMob 管理画面のメディエーショングループに各ネットワークを登録する
サブスクリプション — 継続率がすべてを決める
サブスクの利点は LTV(顧客生涯価値)の大きさですが、「継続する理由」がなければユーザーは静かに去ります。成立条件は3つに集約されると考えています。
サブスク限定機能が「ないと困る」レベルであること — あると便利、では更新月に切られます
月1回以上のアップデートが続く体制 — 開発が止まったサブスクは解約理由になります
無料トライアルで実価値を体験させること — 3〜7日が標準です
価格設計と年払いの効き方
日本の相場感では、軽いユーティリティが ¥480/月、本格的な画像編集やノート系が ¥980/月、専門ツールや継続コンテンツ配信が ¥1,980/月以上。北米では $2.99 / $4.99 / $9.99 が対応する帯です。
必ず用意したいのが 年払い です。月額の8〜10ヶ月分に設定した年額プランは、ユーザーには割引として映り、開発者には前受けのキャッシュと「12ヶ月分のチャーン耐性」をもたらします。月次チャーン 8% の環境では、月払いユーザーの平均継続は約12ヶ月ですが、年払いはその期間の解約がそもそも発生しません。転換ユーザーの2割が年払いを選ぶだけでも、収益の安定度は目に見えて変わります。
Rork(Expo)での実装は RevenueCat が現実解
React Native でのサブスク実装は、StoreKit 2 と Google Play Billing を直接叩くよりも、react-native-purchases(RevenueCat)でラップするのが現在の標準です。レシート検証・復元・プラットフォーム差異の吸収をサービス側が引き受けてくれるため、個人開発では特に効きます。Expo 環境では EAS Build が前提になる点だけ注意してください。
// RevenueCat によるサブスク実装の骨格
import Purchases, { LOG_LEVEL } from 'react-native-purchases' ;
import { Platform } from 'react-native' ;
export async function initPurchases ( userId : string ) {
Purchases. setLogLevel ( LOG_LEVEL . INFO );
Purchases. configure ({
apiKey: Platform. OS === 'ios' ? 'YOUR_RC_IOS_KEY' : 'YOUR_RC_ANDROID_KEY' ,
appUserID: userId,
});
}
export async function purchaseMonthly () {
const offerings = await Purchases. getOfferings ();
const pkg = offerings.current?.monthly;
if ( ! pkg) throw new Error ( 'オファリング未設定' );
const { customerInfo } = await Purchases. purchasePackage (pkg);
return customerInfo.entitlements.active[ 'premium' ] !== undefined ;
}
export async function isPremium () : Promise < boolean > {
const info = await Purchases. getCustomerInfo ();
return info.entitlements.active[ 'premium' ] !== undefined ;
}
トライアルから有料への転換フロー
転換率を左右するのは、トライアル中の体験設計です。効果的だと感じている流れは次のとおりです。
インストール直後は基本機能を無料開放する
プレミアム機能への最初のアクセス試行をトリガーにトライアルを案内する
トライアル終了の2日前に「もうすぐ課金が始まります」と正直に通知する
終了当日の朝に、トライアル中に使った機能を振り返るリマインドを送る
3番目の「課金前の正直な通知」は転換率を下げるように見えて、長期では効きます。意図しない課金で残る1ヶ月分の売上より、ストアレビューと返金率への悪影響のほうがずっと高くつく、というのが私の結論です。Apple も Google も欺瞞的なサブスク誘導には年々厳しくなっています。
買い切り — シンプルさの価値と頭打ちの構造
買い切りは App Store の Pricing Tier を選び、アプリ内で機能を解放するだけ。課金状態の管理も「購入済みか否か」の1ビットで済みます。
向いているのは、単機能ユーティリティ(バーコードスキャナー、単位変換など)、完結型のゲーム、教育・参考書系、デザインツール系。逆に、継続的なサーバーコストが発生するアプリは買い切りと相性が悪い。売上は止まってもコストは止まらないからです。
価格と購買数の関係は線形ではありません。私の経験と市場データを重ねると、おおよそ次の傾向になります。
価格 ダウンロード数(相対) 月間売上の目安(新規1,500件/月)
$1.99 100% $90〜180
$4.99 50% $110〜220
$9.99 20% $90〜180
$19.99 8% $70〜120
価格を上げるほど購買数が大きく落ちるため、ユーティリティ系の最大売上は $2.99〜$4.99 の帯に収まることが多い。値付けに迷ったらこの帯から始めて、セールで弾性を実測するのが安全です。
同一条件での収益試算 — MAU 5,000 の現実的な数字
ここからが核心です。同じアプリを3モデルで展開した場合の月次収益を試算します。先に申し上げると、ネットで見かける試算(以前のこのページに載せていた試算も含みます)には2つの典型的な誤りがあり、それを補正すると景色がかなり変わります。
誤り1: 日次と月次の取り違え。 「DAU 3,000 × 8インプレッション = 24,000」は1日分です。これを月次収益の分子にすると、広告収益を30分の1に過小評価します。
誤り2: MAU と新規数の混同。 「MAU 5,000 の5%が毎月サブスク転換」という置き方は、同じユーザーが毎月転換し続ける計算になっており、非現実的です。転換は基本的に新規インストールから生まれます。
前提条件を揃えます。
MAU: 5,000 / DAU: 3,000 / 月間新規インストール: 1,500
広告: 1 DAU あたり8インプレッション、eCPM $1.50(日本中心)
サブスク: ¥480/月、新規の8%がトライアル開始、トライアルの35%が有料転換、月次チャーン8%
買い切り: $3.99、新規の3%が購入
為替: 1 USD = 150円
ストア手数料: 15%(後述の Small Business Program 適用を前提)
広告モデル
日次インプレッション: 3,000 × 8 = 24,000
月次インプレッション: 24,000 × 30 = 720,000
月次収益: (720,000 / 1,000) × $1.50 = $1,080 ≒ ¥162,000
AdMob の取り分は eCPM に織り込まれているため、ここからストア手数料は引かれません。月次手取り 約¥162,000 。旧版の試算ではこれを「¥5,400」としていました。日次を月次と取り違えるとこれほど違います。
サブスクモデル
月間トライアル開始: 1,500 × 8% = 120人
月間有料転換: 120 × 35% = 42人
定常状態の有料会員数: 42 / 0.08(月次チャーン) = 525人
定常月次売上: 525 × ¥480 = ¥252,000
手数料15%控除後: ¥252,000 × 0.85 = 約¥214,000
定常月次手取り 約¥214,000 。ただし定常に達するまでが長い。この成長曲線では1年でおよそ6割の水準です。立ち上げ初月の手取りは2万円弱で、広告モデルに大きく見劣りします。サブスクは「我慢の期間を資金的・心理的に越えられるか」のモデルだと言えます。
買い切りモデル
月間購入: 1,500 × 3% = 45本
月次売上: 45 × $3.99 = $179.55 ≒ ¥27,000
手数料15%控除後: 約¥23,000
月次手取り 約¥23,000 。新規流入が伸びない限りこの水準で固定されます。
3モデルの比較
指標 広告 サブスク 買い切り
初月の手取り 約¥162,000 約¥17,000 約¥23,000
定常月次手取り 約¥162,000 約¥214,000(約1〜2年後) 約¥23,000
実装難易度 中 高 低
体験への負荷 高 低 なし
収益の予測可能性 低(eCPM変動) 高 中
広告の ¥162,000 は eCPM $1.50 が維持される前提です。冒頭で触れたとおり、eCPM は季節と広告主予算で大きく波打ちます。私のピーク期とその後の落差を踏まえると、広告収益の事業計画は「直近実績の7割」で引くくらいが安全だと考えています。
手数料を 30% と書いている試算は古い
個人開発の規模なら、ストア手数料はもはや30%ではありません。Apple の App Store Small Business Program は年間売上 $1M 未満の開発者の手数料を15%にし、Google Play も最初の $1M までは15%です(2026年6月時点。適用には申請や条件があるため、最新の公式情報をご確認ください)。30%前提の古い試算と比べると、課金系モデルの手取りは2割強も変わります。サブスクと買い切りの試算をするときは、まずこのプログラムの適用可否を確認してください。
ハイブリッド設計 — 無料+広告とサブスクの併用
実務では1モデルに絞らず、「無料+広告」と「サブスク(広告非表示+限定機能)」のハイブリッドが最有力です。課金意思のないユーザーは広告で収益化し、ヘビーユーザーはサブスクで囲い込む。両者の取りこぼしが最小になります。
// ハイブリッドモデルのアクセス制御
import { isPremium } from './purchases' ;
const BASIC_FEATURES = [ 'core-editing' , 'export-jpg' ];
export const FeatureAccess = {
async canUseFeature ( featureId : string ) : Promise < boolean > {
if ( await isPremium ()) return true ;
return BASIC_FEATURES . includes (featureId);
},
async shouldShowAds () : Promise < boolean > {
return ! ( await isPremium ());
},
};
設計のポイントは3つあります。第一に、広告ユーザーの体験を「サブスクへの嫌がらせ」にしないこと。広告が不快すぎるアプリは、サブスク転換より先にアンインストールが起きます。第二に、プレミアム訴求は機能アクセスの瞬間に出すこと。設定画面の奥のバナーは読まれません。第三に、広告削除単体の買い切り(¥480〜¥980程度)を併設すること。サブスクには抵抗があるが広告は消したい、という層は想像以上に厚いです。
Rork と Rork Max での実装の違い
最後に、Rork 系のプロダクトでこれらを実装する際の使い分けです。2026年6月時点で、通常の Rork ($25/月〜)は Expo(React Native)プロジェクトを生成し、Rork Max ($200/月)はネイティブ Swift アプリを生成する別製品です。課金実装の経路がまったく違います。
Rork(Expo)の場合 : ここまで紹介したコード例がそのまま使えます。広告は react-native-google-mobile-ads、サブスクは react-native-purchases。いずれもネイティブモジュールを含むため Expo Go では動かず、EAS Build での開発ビルドが必要です。Rork が生成した直後のプロジェクトに広告 SDK を足す場合は、app.json のプラグイン設定とビルドのやり直しを忘れずに。
Rork Max(Swift)の場合 : StoreKit 2 を直接使えます。Product.purchase() と Transaction.currentEntitlements で完結し、レシート検証も Transaction の署名検証としてフレームワークに組み込まれているため、小規模アプリなら RevenueCat を挟まない選択も現実的です。広告は Google Mobile Ads SDK(iOS ネイティブ版)をそのまま組み込みます。
// Rork Max(Swift)での StoreKit 2 によるサブスク購入
import StoreKit
func purchaseMonthly () async throws -> Bool {
guard let product = try await Product. products ( for : [ "premium_monthly" ]). first else {
return false
}
let result = try await product. purchase ()
if case . success ( let verification) = result,
case . verified ( let transaction) = verification {
await transaction. finish ()
return true
}
return false
}
どちらを選ぶかは収益モデルの観点でも整理できます。広告主体でいくなら、両 OS に同時展開できる Rork(Expo)のほうがインプレッション総量を稼ぎやすい。サブスク主体で Apple エコシステムに深く入るなら、ウィジェットや Live Activities まで使える Rork Max が訴求力で勝ります。
段階的に移行する — 私が勧める順序
長く個人でアプリを運用してきて、最初から完璧な収益モデルを設計しようとするのは時間の使い方として効率が悪い、というのが正直な実感です。勧めたいのは段階移行です。
検証期(MAU 1,000未満) — まず広告だけ実装し、リテンションが成立するかを見ます。この規模でサブスクを作り込んでも、検証に必要な母数が足りません
成長期(MAU 1,000〜5,000) — 広告収益で運営しながらサブスクを追加し、トライアル開始率と転換率を実測します
転換期(MAU 5,000超) — 実測値が前述の試算ラインを越えてきたら、サブスクを主軸に切り替え、広告は無料ユーザー向けの補助に回します
次のアクションとしては、ご自身のアプリの「月間新規インストール数」を確認することから始めてみてください。今回の試算はすべてこの数字から組み立て直せます。MAU ではなく新規数で考える癖がつくと、収益モデルの議論は一気に現実的になります。
同じように収益化の分岐で迷っている方の判断材料になれば幸いです。