react-native-iaptic
v2.0.0
Published
React Native In-App Purchase library with Iaptic receipt validation
Maintainers
Readme
Iaptic React Native SDK
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 →
Table of Contents
- Requirements
- Installation
- Quick Start
- Drop-in Subscription UI
- Core Concepts
- Manual Purchase Flow
- Error Handling
- Troubleshooting
- Upgrading
- Why the fork?
- Documentation
- Support & Community
- Contributing
- Security
- License
✨ Features
- 🛒 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
Requirements
| 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 | ^13.0.0 (peer) |
| react | ≥ 17 (peer) |
| @react-native-async-storage/async-storage | optional — ^3.1.0 or ~2.1.0 (only if using IapticTokensManager) |
Installation
react-native-iaptic requires @iaptic/react-native-iap, an Iaptic-maintained fork of [email protected] with GPBL V9 support, 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.0Expo
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' }]
],
// ...
},
};Quick Start
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.
Drop-in Subscription UI
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
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.
Props reference
| 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 |
Customization
<IapticSubscriptionView
styles={{
productCard: { backgroundColor: '#FFFFFF', borderRadius: 12 },
ctaButton: { backgroundColor: '#4CAF50' },
}}
/>For the full list of overridable style slots, see IapticSubscriptionViewStyles.
Core Concepts
Product definitions
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 },
]);Purchase flow
try {
await IapticRN.order(productOffer);
} catch (error) {
showError(error);
}Restore purchases
try {
await IapticRN.restorePurchases((processed, total) => {
console.log(`Processed ${processed} of ${total} purchases`);
});
} catch (error) {
showError(error);
}Event handling
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}`);
});Feature access control
if (IapticRN.checkEntitlement('premium')) {
showPremiumContent();
} else {
showUpgradePrompt();
}
// All currently active entitlements
const unlocked = IapticRN.listEntitlements(); // ['basic', 'premium', 'cool_feature']Manual Purchase Flow
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
}Error Handling
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);
}
}Troubleshooting
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 upstreamreact-native-iapinstead 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-iapto^13.0.0, which contains GPBL V9 support and the Kotlin fix for RN 0.83+ / new architecture.Android Gradle resolution fails inside
@react-native-async-storage/async-storage— versions2.2.0–3.0.2are broken on Android due to an unpublished Maven artifact. Use^3.1.0or stay on~2.1.0. See release notes for details.
For more, see INTEGRATION_GUIDE.md → Troubleshooting.
Upgrading
From 1.3.x → 2.0.0
- Bump
@iaptic/react-native-iapto^13.0.0for Google Play Billing Library V9 support. This is a breaking change — the fork now requires GPBL 9.0.0 and drops thegetPurchaseHistoryAPI (removed in GPBL V9). Consumers pinning to@iaptic/[email protected]can stay on[email protected]. - Install
@react-native-async-storage/async-storageexplicitly if (and only if) you useIapticTokensManager. It is now an optional peer dependency.
From 1.2.x → 1.3.0
- Install
@react-native-async-storage/async-storageexplicitly if (and only if) you useIapticTokensManager. It is now an optional peer dependency. - Bump
@iaptic/react-native-iapto^12.16.6to pick up the KotlincurrentActivityfix on RN 0.83+.
From 1.0.x → 1.1+
- Install
@iaptic/react-native-iapexplicitly — it moved from a regular dependency to a peer dependency. - The JavaScript API surface and Expo
withIAPplugin behaviour are identical to upstream[email protected].
See RELEASE_NOTES.md for the full changelog.
Why the fork?
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] upgrades Google Play Billing Library to V9, drops the getPurchaseHistory API (removed in GPBL V9), and includes the iOS new-architecture pod fix and the Kotlin currentActivity fix. Consumers who need GPBL V7 can stay on 12.16.6.
Documentation
- 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
Support & Community
- 🐛 Issue tracker — bug reports and feature requests
- 📧 [email protected] — direct support for Iaptic customers
- 🌐 iaptic.com — service status, pricing, dashboard
Contributing
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.
Security
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.
License
MIT © Iaptic
