Androidのサブスクリプションコンバージョン率は、iOSと比較するとプラットフォームの問題のように見えます。RevenueCatが「State of Subscription Apps 2026」レポートのために11万5,000以上のアプリと160億ドル以上の収益を分析したところ、数値は明確でした。AndroidではDay 35時点のダウンロードから課金へのコンバージョン率の中央値は0.9%であるのに対し、iOSでは2.6%です。これはほぼ3倍の差です。この差を見ると、トライアルやユーザー層、あるいはAndroidユーザーの行動そのものに根本的な違いがあるのではないかと考えがちです。しかし、データはそ うではないことを示しています。
同じデータセットをもう一段深く見ると、Androidのトライアルから課金へのコンバージョン率は32.5%、iOSは32.6%となっています。つまり、どちらのプラットフォームでも、一度トライアルを開始したユーザーは統計的にほぼ同じ割合で課金に至っています。ただし重要な注意点があります。Androidではトライアルを開始するユーザー層がより絞り込まれている可能性があります。Androidではそもそもトライアルが表示される機会が少ないため、トライアルを開始するユーザーはより購買意欲が高い傾向にあります。この選択バイアスが、両者のコンバージョン率が近づく理由の一部となっています。それでもなお、主要なレバーは明確です。Androidアプリは、この最初のステージにユーザーを十分に送り込めていません。このギャップを埋めるには、まずより多くのユーザーにトライアルを開始してもらうことから始まります。
本記事では、Androidのペイウォールファネルが2段階で構成されていることと、そのどこでユーザーが離脱しているのか、Google Playのオファーおよびタグシステムがどのサブスクリプションオプションをユーザーに表示するかをどのように制御しているのか、RevenueCatのSubscriptionOptionsの選択ロジックがどのように機能し、どこでサイレントな設定ミスが発生するのか、ハードペイウォールとフリーミアムモデルに関するデータが何を示しているのか、そしてRevenueCat Experimentsを使ってこのギャップを体系的に解消する方法について解説します。
根本的な問題:2つのステージ、そのうち1つが壊れている
ダウンロードから課金に至るまでのユーザージャーニーは、2つの明確なステージに分かれており、それぞれ異なる挙動を示します。
最初のステージは「ダウンロードからトライアル開始まで」です。ユーザーはアプリをインストールし、ペイウォールに到達し、無料トライアルを開始するかどうかを判断します。2つ目のステージは「トライアル開始から課金まで」です。トライアルが終了し、ユーザーがサブスクライバーとして継続するかどうかを決定します。
RevenueCatのデータは、Androidにおいてこの2つのステージの挙動が大きく異なることを示しています。トライアルを開始したユーザーは32.5%の確率で課金に至り、iOSの32.6%とほぼ同じです。しかし、Androidアプリはこの最初のステージに送り込めているユーザー数が大幅に少ないのです。コンバージョンギャップの大部分は、このステージ1に存在しています。
これを具体的に示すデータがあります。トライアル開始の89.4%はインストール当日に発生しています。購買意欲の高いユーザーは、ダウンロード直後に行動します。一方で、インストール当日にトライアルを開始しなかったユーザーは、後から戻って開始することはほとんどありません。つまり、Androidにおける最初のペイウォール表示は、サブスクリプション収益の大半を決定づける瞬間なのです。その後のトライアル体験、オンボーディング、プロダクト自体のパフォーマンスは、AndroidでもiOSでもほぼ同等です。問題は、ユーザーがそもそもその瞬間に到達しているかどうかなのです。
ステージ1:ユーザーがトライアルを見るかどうかを決める要因
Androidでユーザーに無料トライアルが提示されるかどうかは、2つの要素によって決まります。それは「何を表示するか(ペイウォールの種類)」と「いつ表示するか(タイミング)」です。どちらも完全にコントロール可能です。
ペイウォールタイプの差
RevenueCatのデータでは、ペイウォールモデルごとにD35(35日間)のダウンロードから課金へのコンバージョン(最大1ヶ月のトライアル期間をカバーする測定ウィンドウ)が分析されています。コア機能にアクセスする前にサブスクリプションオファーとのインタラクションを必須とするハードペイウォールは、D35コンバージョンの中央値が10.7%です。さらに、上位10%のハードペイウォールアプリでは38.7%に達します。一方で、無料で一部機能を利用できるフリーミアムモデルの中央値は2.1%です。
これはコンバージョンにおいて約5倍の差でありながら、年間リテンションはほぼ同じです。ハードペイウォールは12ヶ月後に27%のサブスクライバーを維持し、フリーミアムは28%です。ほとんどのアプリカテゴリにおいて、ハードペイウォールの数値は大幅に優れています。もしあなたのプロダクトが1回のセッションで明確かつ即時に価値を提供できるのであれば、ハードペイウォールはほぼ確実に適したモデルです。一方で、フリーミアムが適しているのは、ネットワーク効果や価値の発見に時間がかかるカテゴリ――たとえばソーシャルアプリやコミュニティツールのように、収益化の前に広いユーザーベースの獲得が重要な場合です。
| ペイウォールモデル | D35コンバージョン中央値 | 上位10%のD35コンバージョン | 12ヶ月後のリテンション |
|---|---|---|---|
| ハードペイウォール | 10.7% | 38.7% | 27% |
| フリーミアム | 2.1% | — | 28% |
ただし、フリーミアムが後半のコンバージョンで優位性を示すケースが1つあります。6週目時点では、フリーミアムアプリはそのコホートの22.9%をコンバージョンさせるのに対し、ハードペイウォールは15.3%にとどまります。もしプロダクトが数週間かけて徐々に価値を発揮するような長い発見サイクルを持つ場合、フリーミアムはハードペイウォールでは取りこぼしてしまうユーザーを獲得できるのです。
ペイウォール表示タイミングの差
トライアル開始の89.4%がDay 0(初日)に集中しているという事実は、タイミングに対して明確な示唆を与えます。ペイウォールは最初のセッションで表示すべきです。最初のセッション以降は、効果が急速に低下していきます。
ただし、これはオンボーディングの前にペイウォールを表示すべきという意味ではありません。ユーザーがプロダクトの価値を理解する前にペイウォールを表示するアプリは、一般的にオプトイン率が低くなります。効果的なパターンはこうです:まず1つの強い価値体験(1つのタスクの完了、主要機能の提示、具体的なアウトプット)を提供し、その後にペイウォールを表示する。しかも、それをDay 0に行うことです。
見えない失敗:オファー設定ミ スによってトライアルがサイレントに抑制される場合
ペイウォールの種類とタイミングが正しくても、Androidにはもう一つ見落とされがちなトライアル失敗の原因があります。それは、サブスクリプションオファー自体がユーザーに表示されていない可能性です。これはGoogle Playの設定に関する問題であり、エラーが表示されないまま発生することがあります。
Google Playにおけるサブスクリプションオファーの構造
Google Playのすべてのサブスクリプションは、ベースプランと、必要に応じて1つ以上のオファーで構成されます。オファーは、ベースプランの価格に先立つプロモーション価格のフェーズ(無料トライアル、導入価格、またはその両方)を定義します。オファーはBilling Library内では ProductDetails.SubscriptionOfferDetails として表現されます。
各 SubscriptionOfferDetails オブジェクトは、価格フェーズのリスト、オファータグのセット、そして購入を開始するためのオファートークンを持っています。価格フェーズは各ステージの価格と期間を示します。オファータグは、Play Console上でベースプランまたはオファー単位で設定する文字列です。Billing Libraryでは getOfferTags() によって両方のタグの集合(ユニオン)が返されるため、ベースプランに設定したタグは、その下のすべてのオファーにも自動的に適用されます。
RevenueCatがプロダクト情報を取得すると、各 SubscriptionOfferDetails は GoogleSubscriptionOption に変換されます。 subscriptionOptionConversions.kt における変換処理を見ると、以下のようになります:
1internal fun ProductDetails.SubscriptionOfferDetails.toSubscriptionOption(
2 productId: String,
3 productDetails: ProductDetails,
4): GoogleSubscriptionOption {
5 val pricingPhases = pricingPhases.pricingPhaseList.map { it.toRevenueCatPricingPhase() }
6 return GoogleSubscriptionOption(
7 productId,
8 basePlanId,
9 offerId,
10 pricingPhases,
11 offerTags,
12 productDetails,
13 offerToken,
14 presentedOfferingContext = null,
15 installmentPlanDetails?.installmentsInfo,
16 )
17}
offerId はベースプランでは null であり、オファー付きのオプションでは値が設定されます。 The offerToken はユーザーが「無料トライアルを開始」をタップした際に課金フローへ渡されるものであり、The offerTags にはPlay Consoleで割り当てたラベルが含まれます。
RevenueCatがデフォルトオファーを選択する仕組み
プロダクトに GoogleSubscriptionOption オブジェクトのリストが含まれると、RevenueCatはそれらを SubscriptionOptions コレクションにまとめ、 defaultOffer プロパティとして公開します。これは、明示的に別のオプションを選択しない限り、ペイウォール上に表示されるオプションです。
SubscriptionOptions.kt における選択アルゴリズムは次の ように動作します:
1public val defaultOffer: SubscriptionOption?
2 get() {
3 val basePlan = this.firstOrNull { it.isBasePlan } ?: return null
4
5 val validOffers = this
6 .filter { !it.isBasePlan }
7 .filter { !it.tags.contains(RC_IGNORE_OFFER_TAG) }
8 .filter { !it.tags.contains(SharedConstants.RC_CUSTOMER_CENTER_TAG) }
9
10 return findLongestFreeTrial(validOffers) ?: findLowestNonFreeOffer(validOffers) ?: basePlan
11 }
このアルゴリズムでは、まず rc-ignore-offer または rc-customer-center のタグが付いたオファーを除外し、そのうえで最も長い無料トライアル を持つオファーを選択します。もし無料トライアルが存在しない場合は、最も低い導入価格のオファーが選択されます。これらの条件を満たすオファーが存在しない場合、プロモーションフェーズを持たないベースプランにフォールバックします。
このフォールバックこそが、サイレントに発生する失敗です。トライアルオファーに rc-ignore-offer のタグが付いている場合、正しいベースプランに紐づいていない場合、あるいはオファータグがまったく設定されておらずアプリ側がタグベースのフィルタリングに依存している場合、 defaultOffer はベースプランを返します。ペイウォール自体は正常に表示され、見た目も問題ありません。エラーも発生しません。しかし、トライアルは表示されていないのです。
ペイウォールが実際に何を表示しているかを確認する
他の最適化に着手する前に、まずプロダクトの defaultOffer が無料トライアル付きのオファーに解決されていることを確認してください。 SubscriptionOption インターフェースには、まさにこの確認のために freePhase プロパティが用意されています:
1val freePhase: PricingPhase?
2 get() = pricingPhases.dropLast(1).firstOrNull {
3 it.price.amountMicros == 0L
4 }
freePhase が null でない場合、そのオプションには無料トライアルのフェーズが含まれていることを意味します。同様に、introPhase は有料の導入フェーズの有無を確認します。もし defaultOffer の freePhase と introPhase の両方が null であれば、プロモーションフェーズは一切表示されません。また、 defaultOffer?.isBasePlan を直接確認することもできます。これが true の場合、SDKは有効なオファーを見つけられず、ベースプランにフォールバックしたことを意味します。いずれにしても、Play Console上のオファー設定を確認してください。
この確認は、offeringsを取得した後にコード上で行うことができます:
1Purchases.sharedInstance.getOfferingsWith(
2 onError = { error -> /* handle */ },
3 onSuccess = { offerings ->
4 val currentOffering = offerings.current ?: return@getOfferingsWith
5 val monthlyPackage = currentOffering.monthly ?: return@getOfferingsWith
6 val subscriptionOptions = monthlyPackage.product.subscriptionOptions
7
8 val defaultOffer = subscriptionOptions?.defaultOffer
9 val hasFreeTrialOption = defaultOffer?.freePhase != null
10 val hasIntroductoryOffer = defaultOffer?.introPhase != null
11
12 Log.d("Paywall", "Default offer: ${defaultOffer?.id}")
13 Log.d("Paywall", "Has free trial: $hasFreeTrialOption")
14 Log.d("Paywall", "Has intro offer: $hasIntroductoryOffer")
15 }
16)
開発中にこれを実行し、出力結果がPlay Consoleで設定したオファー構成と一致してい ることを確認してください。もし hasFreeTrialOption が false で、トライアルが表示される想定だった場合、そのオファーは選択されていません。オファータグを確認し、オファーが正しいベースプランに紐づいていることを検証し、さらにそのオファーがPlay Console上で有効になっていることを確認してください。
注意すべき構造的な違い
トラッキングや実験に進む前に、AndroidとiOSの比較では完全には捉えきれない、プラットフォームレベルの違いを1つ押さえておく価値があります。
iOSでは、トライアル終了前にAppleがシステムレベルのプッシュ通知を送信し、ユーザーに有料へ移行することを知らせます。一方で、Google Playにはこれに相当するシステム通知は存在しません。つまり、iOSではトライアルから課金への重要なタイミングで、再エンゲージメントの仕組みがプラットフォーム側に組み込まれているのに対し、Androidにはそれがありません。Androidでは、このリマインドは完全にアプリ側の責任となります。アプリ内バナー、自前のバックエンドからのプッシュ通知、あるいはトライアル終了間際にユーザーが戻ってきた際に発動する再エンゲージメントフローなどで対応する必要があります。
この構造的な違いは、トライアル開始ユーザー数が大きく異なるにもかかわらず、トライアルから課金へのコンバージョン率が似て見える理由の一部を説明しています。iOSではコンバージョンのタイミングでプラットフォームによる後押しがあるのに対し、Androidでは同じ結果を得るためには明示的な実装が必要です。もしAndroidのトライアルから課金へのコンバージョン率がiOSより低い場合、その要因の一つとして、トライアル終了リマインダーがアプリ内に存在しないことが考えられます。
PresentedOfferingContextを使ったペイウォールパフォーマンスのトラッキング
オファー設定が正しく行われたら、次のステップは、どのペイウォール配置が最も多くのトライアル開始を生み出しているかを理解することです。RevenueCatの PresentedOfferingContext を使うことで、すべての購入に配置識別子を付与できるようになり、アプリ内のどの位置でペイウォールが表示されたかに基づいて分析をセグメント化できます。
PresentedOfferingContext には3つのフィールドが含まれます:
1public class PresentedOfferingContext(
2 public val offeringIdentifier: String,
3 public val placementIdentifier: String?,
4 public val targetingContext: TargetingContext?,
5)
offeringIdentifier は、RevenueCatダッシュボード上のofferingを指します。 placementIdentifier は、その表示箇所に付けるために自分で定義する文字列で、たとえば"onboarding_paywall"、 "settings_upgrade"、 "feature_gate"などがあります。targetingContext には、RevenueCatのtargeting機能を使用している場合に、そのルールデータが含まれます。
購入を開始すると、このコンテキストはトランザクションとともに渡され、RevenueCatダッシュボードやWebhookイベント上に現れます。これにより、配置ごとのトライアル開始率やD35コンバージョンを比較し、どの表示箇所から優先的に最適化すべきかを判断できるようになります。
トライアル期間:見落とされがちな変数
オファーの可視性やペイウォールの種類に加えて、トライアル期間はトライアルから課金へのコンバージョンに測定可能な影響を与えます。RevenueCatのデータは明確なパターンを示しています:
| トライアル期間 | トライアルから有料へのコンバージョン |
|---|---|
| 4日以下 | 25.5% |
| 17〜32日 | 42.5% |
より長いトライアルを提供しているアプリは、このデータセットにおいてトライアルから有料へのコンバージョンが約17ポイント高くなっています。ただし、これは相関関係であり、長いトライアルを提供するアプリは、単なる設定ではなく、意図的なプロダクト戦略として長いトライアルを 採用している、生産性系やクリエイティブ系のツールである傾向があります。トライアル期間を延ばしたからといって、必ずしも17ポイントの改善が得られるわけではありません。それでもこのパターンは、価値が時間とともに積み上がるタイプのアプリにおいては、4日間のトライアルではユーザーが十分な体験を得る前に終了してしまう可能性があり、14日や30日のトライアルであればプロダクトが価値を示すための十分な時間を確保できることを示唆しています。
それにもかかわらず、このデータセットでは全トライアルの55%が4日以下となっており、前年の42%から増加しています。17日以上のトライアルを提供しているアプリはわずか5%にとどまっています。
もしあなたのトライアルから有料へのコンバージョン率が、Androidの中央値である32.5%を下回っている場合、トライアル期間はテストする価値があります。これは、新たにコードをリリースすることなく、RevenueCat Experimentsで検証できる高インパクトな変数の一つです。
RevenueCat Experimentsによる測定と改善
これまでに説明してきたすべての変数(ペイウォールの種類、タイミング、トライアル期間、オファー選択)は相互に影響し合っており、測定なしに最適解を導くのは困難です。何が効果的かは、プロダクト、ユーザー層、カテゴリによって異なります。
RevenueCat Experiments を使えば、コードのリリースやバックエンド構築を行うことなく、これらの変数に対してA/Bテストを実施できます。RevenueCatダッシュボード上で、トライアル期間、デフォルトオファー、パッケージ構成などが異なるバリアントofferingを作成します。RevenueCatはユーザーをコントロール群とバリアント群にランダムに割り当て、トライアルからコンバージョンまでの行動を追跡し、D35コンバージョン、LTV、トライアル開始率をバリアントごとに可視化します。
実験を開始した後は、CustomerInfo 内の EntitlementInfo.periodType を通じて、ユーザーごとのトライアル状態を監視することができます:
1Purchases.sharedInstance.getCustomerInfoWith(
2 onError = { error -> /* handle */ },
3 onSuccess = { customerInfo ->
4 val premiumEntitlement = customerInfo.entitlements["premium"]
5
6 when (premiumEntitlement?.periodType) {
7 PeriodType.TRIAL -> {
8 // User is in an active trial
9 val trialEnds = premiumEntitlement.expirationDate
10 showTrialExpirationReminder(trialEnds)
11 }
12 PeriodType.INTRO -> {
13 // User is in an introductory paid phase
14 }
15 PeriodType.NORMAL -> {
16 // User is a full subscriber
17 }
18 null -> {
19 // No active entitlement
20 showPaywall()
21 }
22 }
23 }
24)
periodType は、ユーザーのサブスクリプションが現在どのフェーズにあるかを示します。これは、トライアル状態を考慮したUIを構築する際に役立ちます。たとえば、トライアル終了が近づいた際にバナーを表示したり、サブスクリプションのフェーズに応じてメッセージを調整したり、トライアル終了後に課金へ至らなかったユーザーに対して再エンゲージメント用のペイウォールを表示したりすることが可能になります。
まとめ
Androidにおけるコンバージョンギャップは、主にファネル入口の問題であり、その原因は特定可能です。AndroidとiOSの間に見られるD35のダウンロードから課金への約3倍 の差は、プラットフォームの限界を示しているわけではありません。これは、オファー設定ミス、トライアル開始を抑制するフリーミアムモデル、そして遅すぎる、あるいは表示されないペイウォールといった要因が重なった結果です。さらに、構造的な違いも影響しています。iOSはトライアル終了前にシステムレベルの通知を送りますが、Androidにはそれがないため、トライアル終了付近での再エンゲージメントはアプリ側で明示的に実装する必要があります。
このギャップを埋めるための道筋は明確な順序に従います。まず、アクティブなofferingにおける defaultOffer が freePhase を持つオプションに解決されていることを確認してください。そうでなければ、他の変更を行う前にPlay Consoleのオファー設定を修正します。次に、フリーミアムモデルを採用している場合は、ハードペイウォールのバリアントで実験を行い、トライアル開始率と12ヶ月リテンションの両方を測定します。すでにハードペイウォールを採用している場合は、より長いトライアル期間をテストします。そして最後に、PresentedOfferingContextに placementIdentifier を追加し、どの表示箇所がトライアル開始に寄与しているかを把握できるようにします。
これらの変更はすべて測定可能です。RevenueCat Experimentsは推測に頼らずテストを行うための基盤を提供し、D35やトライアルから課金への指標が意思決定のシグナルとなります。
本記事では、Androidのペイウォールコンバージョン問題が2段階ファネルのステージ1に主に存在すること、Google Playのオファーおよびタグシステムがどのサブスクリプ ションオプションを表示するかをどのように決定しているか、RevenueCatの SubscriptionOptions.defaultOffer アルゴリズムがどのようにトライアルを選択し、どこでサイレントな設定ミスが起こり得るのか、ペイウォールモデルやトライアル期間に関するデータが何を示しているか、トライアルリマインダーに関するプラットフォーム間の構造的な違い、そしてRevenueCatのツールを用いた診断と改善方法について解説してきました。
ギャップがどこに存在するかを理解することで、何を構築すべきかが変わります。大半の作業はステージ1にあります。つまり、ユーザーにトライアルを「見せて」「開始してもらう」ことです。トライアルを開始したAndroidユーザーは、iOSユーザーとほぼ同じ確率で課金に至ります。重要なのは、ユーザーにその開始の機会を与え、トライアル終了前に課金へ進む理由を提供することです。

