exporevenuecatin-app-purchasesmonetization

How to Build a Paywall in Expo with RevenueCat (2026 Guide)

In-app subscriptions in Expo with react-native-purchases — SDK setup, config plugin, products, entitlements, and the paywall UI. What works in 2026 and what to avoid.

RevenueCat is the fastest way to add subscriptions to an Expo app: one SDK for the App Store and Google Play, server-side receipt validation, and a ready-made paywall UI. Here is the complete 2026 setup — from package install to a working paywall.

Step 1: Install the SDKs

npx expo install react-native-purchases react-native-purchases-ui

react-native-purchases is the core SDK; react-native-purchases-ui adds prebuilt paywall and customer-center components. The package ships an Expo config plugin — add it so prebuild configures the native side (including the iOS App Tracking Transparency prompt description):

{
  "expo": {
    "plugins": [
      ["react-native-purchases", {
        "ios": {
          "userTrackingUsageDescription": "Your data will be used to personalize your experience."
        }
      }]
    ]
  }
}

Step 2: Create products in the stores first

RevenueCat does not replace store billing — it layers on top of it:

  1. App Store Connect — create auto-renewable subscriptions under your app's subscription group.
  2. Google Play Console — create subscription or one-time products.
  3. RevenueCat dashboard — link both stores' products to shared entitlements (e.g. pro), and group them into offerings — the JSON-like packages your paywall renders.

One entitlement covering both stores is the whole point: your paywall code never asks "which store is this?"

Step 3: Configure the API keys

RevenueCat publishes public SDK keys that are safe to ship in the client. Prefer platform-specific keys in production:

EXPO_PUBLIC_REVENUECAT_IOS_API_KEY=appl_xxxxx
EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY=goog_xxxxx

Then configure the SDK once at startup:

import Purchases from "react-native-purchases";

await Purchases.configure({
  apiKey: Platform.OS === "ios" ? IOS_KEY : ANDROID_KEY,
});

Never ship a secret key (sk_…) in a mobile app. Only appl_, goog_, and test_ keys belong in the client.

Step 4: Render the paywall

The fastest path is RevenueCat's prebuilt paywall (managed from the dashboard):

import { Paywall } from "react-native-purchases-ui";

<Paywall
  onPurchaseCompleted={() => navigation.goBack()}
  onRestoreCompleted={() => navigation.goBack()}
/>

Or check entitlements directly to gate features:

const customerInfo = await Purchases.getCustomerInfo();
const isPro = !!customerInfo.entitlements.active["pro"];

Listen with Purchases.addCustomerInfoUpdateListener so unlocks apply instantly after purchase or restore.

Step 5: Test in sandbox

You cannot test purchases in Expo Go — build a development client:

eas build --profile development --platform ios

Then use sandbox testers (iOS) and license testers (Android) to run through the full purchase, restore, and cancel flow before release.

Skip the wiring entirely

BowlerKit's Expo template ships with RevenueCat already integrated — react-native-purchases + react-native-purchases-ui, the config plugin, platform-specific keys via env, entitlement gating, and a paywall surface ready for your offerings. See the payments docs for the exact configuration, or the quick start to generate a project with monetization pre-wired.