Skip to main content

In-App Purchases And Subscriptions

Quick Answer

The in-app purchase module lives in src/core/inAppPurchase. It provides subscription UI, purchase state, user subscription persistence, and integration with react-native-iap.

Current app packages that use react-native-iap also need react-native-nitro-modules installed alongside it.

Use this module only for apps that sell digital content or subscription access through Apple and Google in-app purchase systems. Physical goods and service payments usually belong in Stripe, PayPal, cash on delivery, or another commerce flow instead.

Source Map

src/core/inAppPurchase
├── IAPManagerWrapped.tsx
├── IMSubscriptionScreen
├── context.ts
├── firebase.ts
├── hooks
└── redux.ts

Important pieces:

File or exportPurpose
IAPManagerWrappedWraps the app with purchase listeners and subscription state.
IMSubscriptionScreenDisplays subscription plans and starts purchases.
IAPConfigProviderProvides product IDs and subscription screen content.
redux.tsStores plans and active subscription state.
firebase.tsPersists user subscription state when Firebase is enabled.

Required Config

Your app config must provide the product IDs that exist in App Store Connect and Google Play Console:

const iapConfig = {
IAP_SKUS: [
'monthly_vip_subscription',
'annual_vip_subscription',
],
subscriptionSlideContents: [
{
title: 'Premium access',
description: 'Unlock premium features.',
},
],
}

If your app still includes IAP_SHARED_SECRET in mobile config, treat it as a migration point. Shared secrets and receipt validation credentials should be moved behind a backend before production release.

Store Setup

At a high level:

  1. Create matching subscription or in-app product IDs in App Store Connect.
  2. Create matching products or subscriptions in Google Play Console.
  3. Add the exact same IDs to IAP_SKUS.
  4. Configure pricing, localization, review metadata, and testing accounts.
  5. Test purchase, restore, cancellation, expiration, and renewal behavior.

Do not ship with demo product IDs. Product IDs are part of the store contract and should be stable once released.

Receipt Validation

The mobile app can start purchases and receive receipts, but production validation should happen on a backend:

  • verify Apple receipts or App Store Server API data server-side;
  • verify Google Play purchase tokens server-side;
  • store subscription status per user;
  • handle renewals, cancellations, refunds, and grace periods;
  • avoid trusting client-only isVIP or isPlanActive flags.

The app module can persist subscription state to Firebase, but your production backend should be the source of truth for entitlement status.

Verification Checklist

Test before release:

  • product IDs load from the store;
  • subscription screen renders real prices;
  • purchase starts and completes;
  • transaction is finished;
  • subscription state is saved to the user profile;
  • restore/available purchases works;
  • expired subscription removes premium access;
  • canceled subscription eventually removes premium access;
  • app handles store errors and user cancellation gracefully.

Troubleshooting

ProblemFix
No products loadConfirm product IDs match exactly and the products are active/testable in store dashboards.
Purchase starts but entitlement is not activeCheck receipt validation and user subscription writes.
iOS receipt validation failsMove validation to backend and confirm the app-specific shared secret or server API credentials.
Android subscription period is wrongConfirm the subscription period string returned by Google Play and the app's period parsing.
App works in debug but fails in releaseTest with real store sandbox/internal testing accounts and release bundle IDs/package names.