react-brain
Browse decisions
React & language foundations 3App architecture 11UI 13Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness benchnewsletterarchitecturechangelogmethodologyroadmap

entriesplatform-native · verified 2026-10-01 · react-native

In-app purchases & payments

reviewedconfidence: mediumthis tier holds 71% on the public scorecard (7/20 graded · 0 overturned) →

re-verified 7× — 2026-10-08 · 2026-09-24 · 2026-09-10 · 2026-09-01 · 2026-08-18 · 2026-08-04 +1 · changelog

recommendation

Subscriptions → RevenueCat (it absorbs receipt validation and entitlement infra). Direct store billing without a third party → expo-iap on Expo, react-native-iap on bare RN; both are the same OpenIAP code, so the runtime picks between them, not liveness. What changes the pick is whether you will run a validation/entitlement backend.

  • small team, subscriptions, no billing backend → RevenueCat (react-native-purchases)
  • one-time purchases or avoiding vendor fees, Expo app → expo-iap (you own validation)
  • one-time purchases or avoiding vendor fees, bare RN app → react-native-iap (you own validation; install @latest, never @next)
  • owning server-side receipt validation on the OpenIAP libraries → @hyodotdev/openiap-commerce-protocol (0.x, evaluate before adopting; not the deprecated unscoped openiap-commerce-protocol)
  • wallet passes (tickets/loyalty/coupons) → @premieroctet/react-native-wallet (set up an Apple Pass Type ID + entitlements; not tap-to-pay)
  • remote paywall config / pricing A-B tests → RevenueCat (its tooling layer, not a separate library decision)

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
expo-iapOpenIAP-compliant IAP as an Expo module (Google Play Billing v8 / Apple StoreKit) without ejecting; you own receipt validation. 5.8.2 (2026-09-30, verified vs npm), released in lockstep with react-native-iap. See note: OPENIAP PACKAGES.339k/wk
react-native-iapThe long-standing community IAP wrapper for bare RN, same OpenIAP code as expo-iap; its standalone repo is archived but the package is NOT deprecated. 16.7.2 (2026-09-30, verified vs npm). Never install @next: see note: DIST-TAG TRAP.171k/wk
RevenueCat (react-native-purchases)Hosted subscription infra + entitlements across stores; fees vs less server work. Remote-configurable paywalls and pricing experiments come with the hosting decision, not as separate choices. 10.10.2 (2026-09-24, verified vs npm).931k/wk
@premieroctet/react-native-walletApple PassKit / Google Wallet passes (tickets, loyalty, coupons), NOT tap-to-pay; iOS needs a Pass Type ID + entitlements. 1.0.2 (2025-06-26) is still the latest release (2026-09-24, verified vs npm): stable-but-quiet, pin it. Not bare react-native-wallet, see note: WALLET NAME.

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

npm weekly downloads (from the corpus's last signals run): react-native-purchases 931k · react-native-iap 171k · expo-iap 339k · @premieroctet/react-native-wallet 3k

Verified notes

THE PICTURE: store rules and receipt validation make IAP testing-heavy, and the real decision is who runs the entitlement backend. RevenueCat rents it to you (fees, less server work); expo-iap and react-native-iap give you the client half and leave validation and cross-store entitlement reconciliation to you. OPENIAP PACKAGES (2026-10-01, verified vs npm): both libraries are released from the hyodotdev/openiap monorepo (the npm repository field of both points there) and still ship in lockstep: react-native-iap 16.7.2 and expo-iap 5.8.2 both on 2026-09-30 (and both on 2026-09-26 before that). The old hyochan/react-native-iap and hyochan/expo-iap repos were archived 2026-04-26 on the way into the monorepo; neither package carries an npm deprecation flag → pick on runtime (Expo module vs bare RN wrapper), not on liveness. expo-iap does not supersede react-native-iap. DIST-TAG TRAP (2026-09-24, verified vs npm): the `next` tag is BEHIND `latest` on react-native-iap (next 15.4.0-rc.3), expo-iap (next 4.4.0-rc.7) and react-native-purchases (next 8.9.1-vc-beta.1) → installing @next silently downgrades you a major. SERVER-SIDE LAYER (2026-09-24, verified vs npm; first recorded 2026-09-02 vs the GitHub release): the OpenIAP Commerce Protocol extends OpenIAP past the client SDKs into a vendor-neutral SERVER-side contract for purchase verification, entitlements, lifecycle events and REST/GraphQL bindings, shipping generated validator artifacts and a portable conformance runner. It now publishes as @hyodotdev/openiap-commerce-protocol (0.3.0, 2026-09-15); the unscoped openiap-commerce-protocol 0.1.0 is deprecated on npm → this is the receipt-validation half the client libraries do not own; still 0.x, so evaluate rather than adopt. OPENIAP BACKING (2026-08-19, verified vs openiap.dev/docs/updates/announcements): OpenIAP is backed by Amazon Developer, and its docs carry store setup for Amazon and Horizon OS alongside Apple/Google → the protocol these libraries implement matters if you ship to Fire OS or Vega OS. WALLET NAME (2026-08-18, verified vs npm): bare react-native-wallet on npm is an unrelated 2020 package (1.0.8, erikpoort, Apple-Wallet-only); the PassKit + Google Wallet library is @premieroctet/react-native-wallet → verify identity (repository field), not existence. HISTORY: 2026-10-01 REOPENED: pins react-native-iap 16.6.2 → 16.7.2, expo-iap 5.6.3 → 5.8.2 — still lockstep (both 2026-09-26 and again 2026-09-30). 2026-09-24 REOPENED: pins react-native-iap 16.5.1 → 16.6.2, expo-iap 5.5.1 → 5.6.3, react-native-purchases 10.7.1 → 10.10.2; commerce protocol moved to the @hyodotdev scope (0.3.0), unscoped 0.1.0 deprecated. 2026-09-10 REOPENED: OpenIAP backed by Amazon; lockstep pins 16.5.1 / 5.5.1; commerce protocol 0.1.0 server contract reconciled from harvest/2026-09-03. 2026-08-18 CORRECTED: the wallet row named bare react-native-wallet (an unrelated 2020 package); the library is @premieroctet/react-native-wallet. Graduated drafted → reviewed. 2026-08-04 CORRECTED: react-native-iap was called "deprecated/archived → prefer expo-iap"; the archived thing was the standalone repo, not the package.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

Cross-platform subscription state: sharing entitlements between Android and iOSJaewoong Eum (RevenueCat)

Why unifying subscription entitlements across iOS/Android is hard — Apple signed-JWS vs Google purchase-token REST, HTTPS notifications vs Cloud Pub/Sub, subscription groups vs base plans/offers — and the four-part DIY architecture. The root reason IAP libraries/services exist.

Building the RC Fortress: protecting payments against outagesRevenueCat Engineering

A resilience case study for keeping purchases working when subscription backends fail — cached paywall snapshots, temporary offline entitlements, buffered request log/replay — with tradeoffs made explicit. The realities of subscription infra regardless of library.

Sources

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About in-app purchases & payments (React Native)

Diataxis: Explanation. This page builds understanding of why buying something inside a mobile app is a backend decision wearing a client-library costume, and why the recommendation splits the way it does. It is not a StoreKit or Play Billing tutorial. Token storage belongs to RB-E-STORAGE, identity to RB-E-AUTH, and "did the purchase actually work in production" to RB-E-OBSERVABILITY. Read this for the why.

The decision is not "which library" — it is "who owns entitlement state"

Every in-app purchase question eventually reduces to one: when your app asks "is this user entitled to the pro features right now?", who answers?

The client library is the easy half. It shows the store sheet, returns a receipt or purchase token, and restores purchases. That part is mechanical, and the two community options do it well.

The hard half is everything after the transaction: validating the receipt somewhere the user cannot tamper with, reconciling renewals and cancellations that happen while the app is closed, handling refunds and grace periods, and surviving the fact that Apple and Google model all of this differently. Apple hands you signed JWS payloads and HTTPS server notifications organised around subscription groups; Google hands you purchase tokens validated over REST with notifications on Cloud Pub/Sub, organised around base plans and offers. Nothing lines up. The first reading in the index entry walks exactly this asymmetry and the four-part architecture a DIY implementation ends up needing — read it before deciding to own this.

So the real question is whether you build that reconciliation service or rent it.

Renting it: RevenueCat

RevenueCat's product is the entitlement service. It ingests both stores' notifications, keeps a per-user entitlement state you query, and gives you the operational surface — remote-configured paywalls, pricing experiments, cohort reporting — that teams otherwise build in-house months later. Those extras are worth naming as features of this choice, not separate decisions to agonise over.

The tradeoff is the usual hosted one: fees, and a vendor in the critical path of revenue. The second reading in the index entry is unusually honest about the second half — it is RevenueCat's own write-up of how they keep purchases working when the backend is unavailable (cached paywall snapshots, temporary offline entitlements, a buffered request log that replays). Read it as the question you should ask any subscription vendor, including this one: what does my app do when you are down?

Owning it: expo-iap and react-native-iap

Both packages come out of the same place — the OpenIAP project (hyodotdev/openiap), which is the useful thing to understand here. They are not competitors so much as two runtimes for one protocol: expo-iap (5.6.3) is the Expo module, react-native-iap (16.6.2) the bare-RN wrapper, and they ship in lockstep — both published 2026-09-19.

That lockstep matters because this entry previously carried the opposite belief. Until 2026-08-04 it said react-native-iap was "deprecated/archived → prefer expo-iap", which read an archived repository as a dead package. The standalone repos (hyochan/react-native-iap, hyochan/expo-iap) were archived 2026-04-26 while the code moved into the monorepo; neither package carries an npm deprecation flag. Pick between them on runtime — Expo module vs bare wrapper — not on liveness.

One trap worth knowing before you install: on both packages the next dist-tag is behind latest (react-native-iap next = 15.4.0-rc.3, expo-iap next = 4.4.0-rc.7, verified 2026-09-24); the same holds for RevenueCat's react-native-purchases (next = 8.9.1-vc-beta.1 against latest 10.10.2). Reaching for @next here silently downgrades you a major version.

Owning it means you also own receipt validation on a server you control, and the testing burden that comes with store sandboxes. That is the fee you pay instead of RevenueCat's.

OpenIAP has started on that server half too. The OpenIAP Commerce Protocol is a vendor-neutral server-side contract for purchase verification, entitlements and lifecycle events, published as @hyodotdev/openiap-commerce-protocol (0.3.0, 2026-09-15; the unscoped openiap-commerce-protocol 0.1.0 is deprecated on npm). It is 0.x: evaluate it before building your validator on it. And since 2026-08-19 OpenIAP is backed by Amazon Developer, with store setup for Amazon and Horizon OS in its docs, so the protocol is no longer only an Apple/Google concern if you ship to Fire OS or Vega OS.

The thing that is not a purchase at all: wallet passes

Tickets, loyalty cards and coupons are Apple PassKit / Google Wallet objects, not purchases, and they are not tap-to-pay. The library is @premieroctet/react-native-wallet (1.0.2), and on iOS you need a Pass Type ID and matching entitlements before any of it runs.

Note the scope. Bare react-native-wallet on npm is an unrelated 2020 package (1.0.8, Apple-Wallet only). This entry named that one by mistake until 2026-08-18 — a reminder that an npm name which resolves is not the same as an npm name resolving to your library. The scoped package is stable but quiet (last published 2025-06-26): pin it, and expect to read its source if the platform moves.

How to read the recommendation

  1. Subscriptions, and you do not want to run a reconciliation service? RevenueCat. Ask the outage question up front.
  2. One-time purchases, or you refuse the vendor fee? expo-iap on Expo, react-native-iap on bare RN — and budget the server-side validation as real work, not a follow-up ticket.
  3. Passes, not purchases? @premieroctet/react-native-wallet, with the Pass Type ID setup.
  4. Whichever you pick, test on real store sandboxes early. Store rules and receipt validation are what make this domain testing-heavy; no library removes that.

Related in platform-native: native · media · storage · native-ui · keyboard · brownfield · games · alt-frameworks