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
option
tradeoff
evidence
expo-iap
OpenIAP-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-iap
The 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-wallet
Apple 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.
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.
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.
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.
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 behindlatest (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
Subscriptions, and you do not want to run a reconciliation service? RevenueCat. Ask the
outage question up front.
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.
Passes, not purchases?@premieroctet/react-native-wallet, with the Pass Type ID setup.
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.