In-App Purchases in React Native 2026: RevenueCat vs Rolling Your Own with StoreKit 2 and Google Play Billing 7
A practical breakdown of shipping subscriptions in a React Native app in 2026 — when RevenueCat earns its cut, and when writing directly against StoreKit 2 and Play Billing 7 is the saner call.
Every mobile team hits the same fork in the road the week subscriptions land on the roadmap: do we integrate RevenueCat and be done, or do we bite the bullet and talk to StoreKit 2 and Google Play Billing 7 directly? In 2026 the answer is less obvious than it was two years ago, because both platforms have shipped genuinely nicer APIs — and RevenueCat's pricing sits in a different place than it used to.
This is what we tell clients when they ask.
The real job of an IAP layer
Before comparing SDKs, it helps to name what an in-app purchase system actually has to do. It's not "call purchase() and grant the user access". The unglamorous work is:
- Fetching products and prices in the user's local currency, with the right introductory offer eligibility
- Handling the purchase flow, including interrupted purchases and Ask to Buy on iOS
- Verifying the receipt server-side so a jailbroken client can't hand you a forged entitlement
- Tracking entitlements across devices and reinstalls (the "restore purchases" button that everyone forgets)
- Reacting to renewals, refunds, grace periods, billing retry, and price changes via server-to-server notifications
- Surfacing all of that in analytics so growth can actually reason about LTV
Any option you pick has to cover all of it. The question is who writes and maintains that code.
Option A: RevenueCat
RevenueCat is still the default recommendation for most teams, and for good reason. Their react-native-purchases SDK abstracts both stores behind one API, they run the receipt validation servers, and they handle the store webhooks so you don't have to stand up an APNs-adjacent endpoint just to know a user churned.
A typical Expo integration looks roughly like this:
import Purchases from 'react-native-purchases';
await Purchases.configure({
apiKey: Platform.select({
ios: process.env.EXPO_PUBLIC_RC_IOS_KEY!,
android: process.env.EXPO_PUBLIC_RC_ANDROID_KEY!,
})!,
appUserID: user.id, // your own stable ID, not the anonymous one
});
const offerings = await Purchases.getOfferings();
const pro = offerings.current?.availablePackages[0];
if (pro) {
const { customerInfo } = await Purchases.purchasePackage(pro);
const isPro = customerInfo.entitlements.active['pro'] !== undefined;
}
That's it. No receipt parsing, no SKPaymentTransactionObserver, no BillingClient lifecycle. Entitlements are a first-class concept, so your app checks "does this user have pro?" rather than "do they own SKU com.app.pro_monthly_v3?" — which matters the first time product marketing renames a SKU.
Where RevenueCat earns its cut
- Cross-platform parity. One entitlement model that works identically on iOS and Android saves a real amount of glue code.
- Webhooks and integrations. Out-of-the-box hooks into Mixpanel, PostHog, Braze, Segment, Slack, and your own backend. Building the equivalent yourself is a week you didn't budget.
- Sandbox debugging. Their dashboard shows the actual purchase events landing in real time, which is worth an afternoon of
console.logon its own the first time a sandbox purchase silently fails. - Paywall A/B testing. Their remote paywalls and experiments have matured enough that growth teams can iterate without a store build.
Where it starts to sting
RevenueCat's pricing model is revenue-share above a monthly threshold. If you're pre-product-market-fit, you'll pay nothing. If you cross into serious MRR, that share becomes a line item that someone in finance will eventually circle in red. It's not unreasonable for what you get, but it is a permanent tax on revenue you already earned.
The other real cost is the dependency itself. You're routing every purchase event through a third party's infrastructure. Their uptime is good, but it's another SLA you don't control, and another SDK that occasionally lags a new iOS beta by a week or two.
Option B: Rolling your own on StoreKit 2 and Play Billing 7
The reason this option is more attractive in 2026 than it was in 2023 is that both native APIs have gotten dramatically better.
StoreKit 2 (iOS 15+) is Swift-first, async/await-native, and — critically — includes JWS-signed transactions you can verify server-side without hitting Apple's /verifyReceipt endpoint. The old world of parsing base64 receipts and worrying about shared secrets is essentially gone if you're willing to drop iOS 14.
Google Play Billing 7 consolidated the subscription model around base plans and offers, and the server-side Real-Time Developer Notifications v2 payload is finally consistent enough to build against without a shelf of edge-case handlers.
A React Native team going this route typically reaches for react-native-iap (Expo config plugin available) or writes a thin Expo module wrapping the native APIs directly. The client side is manageable. The server side is where the work lives.
What you're signing up to build
- A products endpoint that mirrors your store configuration so the app doesn't ship a hardcoded SKU list
- Receipt/JWS verification for iOS and a Play Developer API integration for Android
- Webhook endpoints for App Store Server Notifications v2 and Google RTDN, with idempotent handlers because both platforms will absolutely deliver the same event twice
- An entitlements table keyed by your user ID, not the store's transaction ID, so cross-device restore works
- Reconciliation jobs for the edge cases webhooks miss (they will miss some)
- Alerting when any of the above breaks silently
In our experience, a competent backend engineer can get a first version of this into production in two to four weeks, and then spend another month shaking out the long tail of refunds, family sharing, upgrades/downgrades, and grace-period behavior. It is not a weekend project.
When it's the right call
- You already have a mature backend team and an on-call rotation
- Your projected revenue makes RevenueCat's share meaningfully larger than the engineering cost
- You have compliance or data-residency requirements that make routing purchase events through a US vendor awkward
- You need custom purchase logic (metered billing, hybrid one-time + subscription, B2B seats) that doesn't fit the entitlement model cleanly
A decision framework we actually use
When a client asks us which way to go, we run through roughly this checklist:
- What's the 12-month revenue projection? Below a modest threshold, RevenueCat is free or nearly so. Above it, do the math on their pricing page against your projected MRR.
- Does the team have backend capacity now? Not "eventually" — this quarter. If not, RevenueCat buys you time.
- How exotic is the monetization? Standard auto-renewing subs? Either works. Consumables plus subs plus promotional codes plus web-purchased entitlements that need to sync into the app? RevenueCat's model was built for this.
- How much does the growth team want to iterate on paywalls? If the answer is "constantly", remote paywalls without a store build is a killer feature.
- What's the exit cost? RevenueCat lets you export transactions, but migrating live subscribers off any IAP abstraction is genuinely painful. Assume you're picking for the next three years.
Things both options get wrong by default
Regardless of which path you pick, a few pitfalls will bite you:
- Anonymous IDs. If you let the SDK generate its own user ID before login, you'll have orphan entitlements the first time someone reinstalls. Always pass your own stable ID.
- Restore purchases button. Apple's review team will reject builds that don't have one, visibly, on the paywall. This is one of the most common React Native rejections we still see — worth reading our App Review breakdown if you haven't.
- Sandbox ≠ production. Sandbox renewals happen every few minutes on iOS. Do not tune your webhook logic against sandbox timing.
- Price changes. Both stores now require explicit consent flows for price increases on existing subscribers. Test this before you need it.
- Family sharing on iOS. If you enable it on a product, the purchaser and family members get separate transactions. Your entitlement logic has to expect that.
Where we'd start
For most React Native teams shipping their first paid tier in 2026, we'd start with RevenueCat, be honest about it as a build-vs-buy decision, and revisit at the revenue level where the share crosses roughly one engineer-month per quarter. Ship the paywall, learn what users actually pay for, and only then decide whether owning the stack end-to-end is worth the ongoing maintenance.
If you're already past that revenue line, or you have a backend team that would rather own the pipeline than integrate another vendor, StoreKit 2 and Play Billing 7 are finally pleasant enough to build against directly — as long as you budget for the server-side work honestly. If you'd like a second pair of eyes on either path, that's the kind of thing our mobile team does most weeks.
Want a team like ours?
72Technologies builds production software for the kind of teams who actually read this blog.
Start a projectKeep reading

Background Tasks in React Native 2026: What Still Breaks on iOS and Android
Background execution is where cross-platform promises go to die. Here's what actually runs on iOS 18 and Android 15 in 2026, where Expo helps, and when you have to drop into Swift or Kotlin.

Surviving App Store Review in 2026: The React Native Rejections We Keep Seeing
A field guide to the App Store and Play Store rejections that hit React Native and Expo apps hardest in 2026 — and how to ship a build that actually gets through on the first try.

Push Notifications in React Native 2026: Expo Notifications vs FCM vs OneSignal in Production
We've shipped push on all three stacks — Expo Notifications, raw FCM/APNs, and OneSignal. Here's how they actually behave in production, including the token-refresh bugs nobody warns you about.
