はじめに 導入背景 バックエンドで直面した課題 RevenueCat の魅力 Webhook によるイベント通知 ダッシュボード A/B テスト基盤がある 実際に使って感じたメリット 工夫した点 サブスクリプションの有効期限が切れているにも関わらずプレミアムステータスのままのユーザーがいればステータスを切り替えるバッチを作成 まとめ 参考 この記事は every Tech Blog Advent Calendar 2025 の 2 日目の記事です。 はじめに こんにちは、トモニテで開発を担当している吉田です。 今年 6 月末、弊社サービス「トモニテ」でサブスクリプションサービスのトモニテプレミアムサービスをリリースしました(iOS のみ、2025/11/28 時点)。サブスクリプション機能を実装するにあたり、バックエンド側でレシート検証やステータス管理の実装に多くの工数がかかることが課題でした。 そこで、サブスクリプション管理に RevenueCat を導入しました。本記事では、バックエンドエンジニアの視点から、RevenueCat を運用してみて感じたことについて紹介します。 導入背景 バックエンドで直面した課題 iOS, Android で異なるところもありますがアプリからの購読登録のざっくりフローは以下の通りです。 アプリからストアへ購読の決済要求 ストアからレシートの発行 レシートをサーバーで検証 検証後アプリでユーザーのステータス更新 主にサーバー側で対応する必要があるのは 3,4 になります。 レシートについては Apple(App Store)と Google(Google Play Store)で形式や記載内容が異なるためそれぞれのプラットフォーム用に処理を用意する必要があります。 またトモニテプレミアムはサブスクリプションサービスなのでユーザーのサブスクリプションステータスの変更をモニタリングしステータスの変更処理もする必要があります。 両プラットフォームでサーバー通知があり、iOS では App Store Server Notifications を、Android では Real-time Developer Notifications(RTDN) を利用して変更を通知できます。 このサーバー通知を受け取るために iOS では ATS プロトコルを使用してサーバーと安全なネットワーク接続を確立する必要があります。Android は Google Cloud Pub/Sub が使用されるためそのセットアップが必要になります。(Pub/Sub に関しては必須ではありませんが、利用しない場合には Google Play Developer API をポーリングする必要があります) 加えて通知で受け取った情報と最新のレシートを照らし合わせてサブスクリプションステータスを検証する処理を準備する必要があり、それも両プラットフォーム用に作成する必要があります。 まとめると以下の対応を ×2 ずつする必要があります。(もし今後 web からの課金が増える場合にはその対応も増えることになる) 購読開始時のレシート検証 サブスクリプションのサーバー通知対応 1,2 の各種メンテナンス 上記経緯からレシート検証の自動化が実現できて直感的なダッシュボードが提供され、分析機能も充実している RevenueCat を導入することにしました。 RevenueCat の魅力 RevenueCat にはたくさんの機能が提供されていますが、個人的には以下が特にいいなと思っています。 Webhook によるイベント通知 RevenueCat にもプラットフォームと同様にサブスクリプションイベントに関するリアルタイム通知が存在します。イベント発生のたびに指定したエンドポイントにデータが送信されます。弊社では送られたデータをいくつかピックアップし自社サーバーに保存して社内の管理画面でユーザーのステータスを確認できるようにしています。また Webhook を利用しサブスクリプションのライフサイクルに基づいてワークフローを起動できたり、発生したイベントに対してユーザーに通知を実行することもできます(解約操作をしたユーザーにサブスクリプションサービスの魅力を提示するなど)。 また送信に失敗(サーバーからステータスコード 200 が返らなかった)しても実行間隔を延ばしながら 5 回リトライしてくれます。 実際に受け取ったリクエストボディは以下になります。(sandbox 環境下、2025/11/17 時点) app_user_id は独自に設定しています { " api_version ": " 1.0 ", " event ": { " aliases ": [ " $RCAnonymousID:<RevenueCatが生成したランダムなアプリユーザーID> ", " <customed_app_user_id> " ] , " app_id ": " <app_id> ", " app_user_id ": " <customed_app_user_id> ", " commission_percentage ": 0.1364 , " country_code ": " JP ", " currency ": " JPY ", " entitlement_id ": null , " entitlement_ids ": [ " Premium " ] , " environment ": " SANDBOX ", " event_timestamp_ms ": 1763356620218 , " expiration_at_ms ": 1763357148000 , " id ": " <id> ", " is_family_share ": false , " is_trial_conversion ": false , " metadata ": null , " offer_code ": null , " original_app_user_id ": " <customed_app_user_id> ", " original_transaction_id ": " <original_transaction_id> ", " period_type ": " NORMAL ", " presented_offering_id ": " paywall_v2 ", " price ": 41.399 , " price_in_purchased_currency ": 6400 , " product_id ": " PlanAnnually ", " purchased_at_ms ": 1763353548000 , " renewal_number ": 20 , " store ": " APP_STORE ", " subscriber_attributes ": { " $adjustId ": { " updated_at_ms ": 1750735215184 , " value ": " <adjustId> " } , " $attConsentStatus ": { " updated_at_ms ": 1749721029062 , " value ": " denied " } , " $deviceVersion ": { " updated_at_ms ": 1760408728747 , " value ": " iPhone12,1-iOS-Version 18.5 (Build 22F76) " } , " $firebaseAppInstanceId ": { " updated_at_ms ": 1762771906755 , " value ": " <firebaseAppInstanceId> " } , " $idfa ": { " updated_at_ms ": 1750735215021 , " value ": " <idfa> " } , " $idfv ": { " updated_at_ms ": 1750735215021 , " value ": " <idfv> " } , " $ip ": { " updated_at_ms ": 1763027995620 , " value ": " <ip_address> " } , " route ": { " updated_at_ms ": 1750323201312 , " value ": " mypage " } } , " takehome_percentage ": 0.85 , " tax_percentage ": 0.0909 , " transaction_id ": " <transaction_id> ", " type ": " RENEWAL " } } ダッシュボード RevenueCat のダッシュボードでは iOS, Android それぞれのデータを一元管理できる他、アプリの収益も確認できます。 Charts & Metrics セクションでは、収益、サブスクリプション、コホートと LTV、コンバージョンファネル、トライアル、解約と返金、未完了期間などの概要メトリクスを確認できます。またコード不要で後述の A/B テストの管理もできます。 A/B テスト基盤がある RevenueCat Experiments というモバイルサブスクリプションアプリビジネスの価格設定とペイウォール設計の最適化に特化した A/B テスト機能があります。こちらは offering(ペイウォールで提示する製品、トライアル期間、価格などのパッケージのこと)を定義し、新規ユーザーに対しコントロール群とトリートメント群の割り当てを行いユーザーに割り当てられたグループに応じたペイウォールが表示されます。出し分けるだけでなく実験開始から 24 時間以内に実験結果を確認することができます。 実際に使って感じたメリット 使ってみて、開発工数の削減が最も大きなメリットだと感じました。レシート検証やステータス管理の実装が不要になったため、プレミアムサービスの機能実装により多くの時間を割くことができました。 工夫した点 サブスクリプションの有効期限が切れているにも関わらずプレミアムステータスのままのユーザーがいればステータスを切り替えるバッチを作成 Webhook はリトライを 5 回までしてくれると前述しましたがそれでも絶対にデータを取りこぼすことがないとは言い切れません。もし定期購入していないにも関わらずプレミアムステータスのままのユーザーがいればそれは弊社の売り上げ棄損にも繋がります。 RevenueCat が提供している API ではサブスクリプションの有効期限切れのユーザーを洗い出すような機能は提供されていなかったため、自社サーバーに保存しているデータに対して有効期限が切れているにも関わらずプレミアムステータスのままのユーザーがいればステータスを切り替えるバッチを作成しました。 また Webhook は基本的には イベント後5~60 秒の間に通知がされるようになっていますがキャンセルイベントは最大 2 時間の遅延が発生するとなっていたのでバッチではこちらを考慮するようにしています。 遅延について Most webhooks are usually delivered within 5 to 60 seconds of the event occurring - cancellation events usually are delivered within 2hrs of the user cancelling their subscription. You should be aware of these delivery times when designing your app. まとめ RevenueCat を導入することで、サブスクリプション管理に関する開発工数を大幅に削減できました。これにより、プレミアムユーザーサービスの機能実装により多くの時間を割くことができ、6 月末のリリースに間に合わせることができました。RevenueCat がなければ、このタイミングでのリリースは難しかったと感じています。 導入から 5 ヶ月ほど経過していますが、RevenueCat 起因の問題は発生しておらず、安定して運用できています。 同様の課題を抱えている方の参考になれば幸いです。 参考 www.revenuecat.com developer.apple.com developer.android.com