react-native-iaptic

Iaptic React Native SDK

npm version npm downloads types included License: MIT Made by Iaptic

Drop-in subscription paywall and server-validated in-app purchases for React Native, backed by the Iaptic service. Works on iOS (StoreKit) and Android (Google Play Billing), with first-class TypeScript support.

What is Iaptic? Iaptic is a hosted receipt-validation and subscription-management service. The SDK never trusts a local receipt — every purchase is verified server-side. Learn more →

IapticSubscriptionView drop-in UI screenshot
The IapticSubscriptionView drop-in paywall, rendered on iOS.

  • 🛒 Unified iOS + Android purchasing API
  • 🔄 Subscription tracking with renewal events
  • 🔒 Server-side receipt validation via Iaptic
  • 🎨 Themable drop-in paywall (IapticSubscriptionView)
  • 📦 Product catalog with entitlements model
  • 🛡 Typed errors with localized messages
  • 🪙 Optional token/credit tracking (IapticTokensManager)
  • ⚛️ First-class TypeScript types
Requirement Version
React Native ≥ 0.71 (tested through 0.85)
Expo SDK ≥ 49 (new architecture supported on SDK 55+)
iOS deployment target 13.0
Android minSdkVersion 24
Node ≥ 18
TypeScript ≥ 4.7 (types ship with the package)
@iaptic/react-native-iap ^12.16.6 (peer)
react ≥ 17 (peer)
@react-native-async-storage/async-storage optional — ^3.1.0 or ~2.1.0 (only if using IapticTokensManager)

react-native-iaptic requires @iaptic/react-native-iap, an Iaptic-maintained fork of [email protected] with the iOS new-architecture pod fix and the Kotlin currentActivity fix baked in. See Why the fork? below.

npm install @iaptic/react-native-iap react-native-iaptic
# iOS only
cd ios && pod install && cd ..

# Only if using IapticTokensManager (consumable token tracking):
npm install @react-native-async-storage/async-storage@^3.1.0

Add the config plugin to your app.json / app.config.js so the Android missingDimensionStrategy (Play Store flavor) is wired up at prebuild time:

// app.config.js
export default {
expo: {
plugins: [
['@iaptic/react-native-iap', { paymentProvider: 'Play Store' }]
],
// ...
},
};
import { IapticRN } from 'react-native-iaptic';

IapticRN.initialize({
appName: 'app.example.com',
publicKey: 'YOUR_PUBLIC_KEY',
iosBundleId: 'com.yourcompany.app',
products: [
{ id: 'premium_monthly', type: 'paid subscription', entitlements: ['premium'] },
{ id: 'coins_100', type: 'consumable', tokenType: 'coins', tokenValue: 100 },
],
});

That's the minimum needed to load products. From here you can either drop in the prebuilt subscription UI, or wire up the manual purchase flow yourself.

IapticSubscriptionView is a full-screen subscription picker with built-in purchase, restore, and active-subscription management. Render it once near your app root and open it on demand.

IapticSubscriptionView on iOS

<IapticSubscriptionView
entitlementLabels={{
premium: {
label: 'Premium Features',
detail: 'Exclusive content and advanced tools',
},
}}
onPurchaseComplete={() => {
setEntitlements(IapticRN.listEntitlements());
}}
termsUrl="https://yourdomain.com/terms"
/>

The component automatically handles landscape/portrait layouts, localization, purchase states, active-subscription management, and receipt validation.

Prop Type Description
entitlementLabels Record<string, { label: string, detail?: string }> Labels and descriptions for each entitlement
onPurchaseComplete () => void Callback after successful purchase
termsUrl string URL for terms & conditions
theme IapticTheme Customize colors — see IapticTheme
styles Partial<IapticSubscriptionViewStyles> Per-element style overrides — see IapticSubscriptionViewStyles
<IapticSubscriptionView
styles={{
productCard: { backgroundColor: '#FFFFFF', borderRadius: 12 },
ctaButton: { backgroundColor: '#4CAF50' },
}}
/>

For the full list of overridable style slots, see IapticSubscriptionViewStyles.

Products can be subscriptions, consumables, or non-consumables. Each can grant one or more entitlements:

IapticRN.setProductDefinitions([
// Subscription that unlocks premium features
{ id: 'premium_monthly', type: 'paid subscription', entitlements: ['premium'] },

// Non-consumable that unlocks a specific feature
{ id: 'dark_theme', type: 'non consumable', entitlements: ['cool_feature'] },

// Consumable tokens / currency
{ id: 'coins_100', type: 'consumable', tokenType: 'coins', tokenValue: 100 },
]);
try {
await IapticRN.order(productOffer);
} catch (error) {
showError(error);
}
try {
await IapticRN.restorePurchases((processed, total) => {
console.log(`Processed ${processed} of ${total} purchases`);
});
} catch (error) {
showError(error);
}
IapticRN.addEventListener('subscription.updated', (reason, purchase) => {
console.log(`Subscription ${purchase.id} ${reason}`);
});

IapticRN.addEventListener('pendingPurchase.updated', (pendingPurchase) => {
console.log(`Purchase ${pendingPurchase.productId} is now ${pendingPurchase.status}`);
});

IapticRN.addEventListener('purchase.updated', (purchase) => {
console.log(`Purchase ${purchase.id} ${purchase.status}`);
});
if (IapticRN.checkEntitlement('premium')) {
showPremiumContent();
} else {
showUpgradePrompt();
}

// All currently active entitlements
const unlocked = IapticRN.listEntitlements(); // ['basic', 'premium', 'cool_feature']

If you don't want the drop-in UI, drive purchases yourself:

const offer = IapticRN.getProduct('premium_monthly')?.offers[0];
if (offer) {
await IapticRN.order(offer);
}

if (IapticRN.checkEntitlement('premium')) {
// Unlock premium features
}
function showError(error: Error | IapticError) {
if (error instanceof IapticError) {
trackAnalyticsEvent(error.code);
if (error.severity === IapticSeverity.INFO) {
console.log('Info:', error.localizedMessage);
return;
}
Alert.alert(error.localizedTitle, error.localizedMessage);
} else {
Alert.alert('Unknown error', error.message);
}
}
  • Products won't load on iOS — verify your Xcode project has the In-App Purchase capability enabled (Xcode → Project → Targets → your app → Signing & Capabilities → + Capability → In-App Purchase).

  • iOS build fails on React Native ≥ 0.83 / Expo SDK ≥ 55 with Unable to find a specification for RCT-Folly depended upon by RNIap — you're depending on upstream react-native-iap instead of @iaptic/react-native-iap. Switch to the fork (see Installation) and the error goes away. Background: Why the fork?.

  • Android build fails with Unresolved reference 'currentActivity' — bump @iaptic/react-native-iap to ^12.16.6, which contains the Kotlin fix for RN 0.83+ / new architecture.

  • Android Gradle resolution fails inside @react-native-async-storage/async-storage — versions 2.2.03.0.2 are broken on Android due to an unpublished Maven artifact. Use ^3.1.0 or stay on ~2.1.0. See release notes for details.

For more, see INTEGRATION_GUIDE.md → Troubleshooting.

  • Install @react-native-async-storage/async-storage explicitly if (and only if) you use IapticTokensManager. It is now an optional peer dependency.
  • Bump @iaptic/react-native-iap to ^12.16.6 to pick up the Kotlin currentActivity fix on RN 0.83+.
  • Install @iaptic/react-native-iap explicitly — it moved from a regular dependency to a peer dependency.
  • The JavaScript API surface and Expo withIAP plugin behaviour are identical to upstream [email protected].

See RELEASE_NOTES.md for the full changelog.

Upstream hyochan/react-native-iap was archived on 2026-04-26; development moved to the OpenIAP monorepo, where it shipped as a Nitro Modules rewrite (v15+, different API). The 12.x line therefore won't receive any further patches upstream — including the iOS pod fix needed for React Native ≥ 0.83 / Expo SDK ≥ 55 / new architecture (Unable to find a specification for RCT-Folly depended upon by RNIap), and the Kotlin currentActivity fix for the same RN versions.

@iaptic/[email protected] is 12.16.4 with those fixes applied — JavaScript / Java / Kotlin / Obj-C / Swift code is otherwise byte-identical to upstream 12.16.4. Skeptical readers can verify by browsing the fork's commit history.

  • Integration guide — step-by-step setup for subscriptions (single reference combining install, dashboard, example app, and API)
  • API reference — generated TypeDoc for all public types
  • Release notes — changelog and upgrade notes
  • Demo app — a runnable example app

This repository is maintained by Iaptic. PRs and issue reports are welcome — please file an issue first for non-trivial changes so we can align on direction before you invest the work.

Receipts are validated server-side by Iaptic; no validation logic runs in the app bundle, and your validation secret never ships to clients. To report a security issue, email [email protected] rather than opening a public GitHub issue.

MIT © Iaptic