A robust in-app purchase library for React Native that simplifies receipt validation and subscription management through the Iaptic service.
- π Unified Purchasing API - Single interface for iOS and Android
- π Subscription Management - Easy status tracking and renewal handling
- π Secure Receipt Validation - Server-side validation via Iaptic
- π‘ Error Handling - Comprehensive error codes and localization
- π¦ Product Catalog - Structured product definitions with pricing phases
- π Entitlement Tracking - Real-time purchase state management
react-native-iaptic depends on two peer modules: @iaptic/react-native-iap (an Iaptic-maintained fork of react-native-iap@12.16.4 with the iOS new-architecture pod fix baked in β see Why the fork below) and @react-native-async-storage/async-storage.
npm install @iaptic/react-native-iap @react-native-async-storage/async-storage
npm install react-native-iaptic
cd ios && pod install && cd ..
β οΈ Upgrading from 1.0.x? Install@iaptic/react-native-iapand@react-native-async-storage/async-storageexplicitly β they moved to peer dependencies. The JavaScript API surface and ExpowithIAPplugin behaviour are identical to upstreamreact-native-iap@12.16.4.
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'],
// ...
},
};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). @iaptic/react-native-iap@12.16.5 is 12.16.4 with that one fix applied β JavaScript / Java / Obj-C / Swift code is otherwise byte-identical to upstream 12.16.4.
Here's a complete example to get you started:
import { IapticRN } from 'react-native-iaptic';
// 1. Initialize with your configuration
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
}
]);The IapticSubscriptionView component provides a complete subscription management interface with purchase handling.
// In your root node, add the modal component
<IapticSubscriptionView
entitlementLabels={{
premium: {
label: "Premium Features",
detail: "Exclusive content and advanced tools"
}
}}
onPurchaseComplete={() => {
// Update app state after purchase
setEntitlements(IapticRN.listEntitlements());
}}
termsUrl="https://yourdomain.com/terms"
/>| 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 |
object |
Customize colors (see IapticTheme) |
// AppState.ts
interface AppState {
entitlements: string[];
}
// In your component
<TouchableOpacity
onPress={() => checkAccess('premium')}
style={styles.button}
>
<Text>
Premium Access: {appState.entitlements.includes('premium') ? 'β
' : 'π'}
</Text>
</TouchableOpacity>Customize styles using the styles prop:
<IapticSubscriptionView
styles={{
productCard: {
backgroundColor: '#FFFFFF',
borderRadius: 12
},
ctaButton: {
backgroundColor: '#4CAF50'
}
}}
/>The component automatically handles:
- Landscape/portrait layouts
- Localization
- Purchase states
- Active subscription management
- Receipt validation
// 4. Handle purchases
const offer = IapticRN.getProduct('premium_monthly')?.offers[0];
if (offer) {
await IapticRN.order(offer);
}
// 5. Check access
if (IapticRN.checkEntitlement('premium')) {
// Unlock premium features
}Products can be subscriptions, consumables, or non-consumables. Each product 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
}
]);Handle purchases with proper error management:
try {
await IapticRN.order(productOffer);
} catch (error) {
showError(error);
}Allow users to restore their previous purchases:
try {
await IapticRN.restorePurchases((processed, total) => {
console.log(`Processed ${processed} of ${total} purchases`);
});
}
catch (error) {
showError(error);
}Listen for purchase and subscription updates:
// Listen for subscription updates
IapticRN.addEventListener('subscription.updated', (reason, purchase) => {
console.log(`Subscription ${purchase.id} ${reason}`);
});
// Listen for pending purchase updates
IapticRN.addEventListener('pendingPurchase.updated', (pendingPurchase) => {
console.log(`Purchase ${pendingPurchase.productId} is now ${pendingPurchase.status}`);
});
// Listen for purchase updates
IapticRN.addEventListener('purchase.updated', (purchase) => {
console.log(`Purchase ${purchase.id} ${purchase.status}`);
});Check if users have access to specific features:
// Check premium access
if (IapticRN.checkEntitlement('premium')) {
showPremiumContent();
} else {
showUpgradePrompt();
}
// List all active entitlements
const unlockedFeatures = IapticRN.listEntitlements();
// ['basic', 'premium', 'cool_feature']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);
}
}For complete API documentation, visit our API Reference.
-
If your app fails to load products, check that your XCode project contains the "In-App Purchase" capability (XCode -> Project -> Targets (your app name) -> Capabilities). Hit "+ Capability" and add the In-App Purchase capability if it's missing.
-
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 using upstreamreact-native-iapinstead of@iaptic/react-native-iap. Switch to the fork (see Installation) and the error goes away. Background on why the fork exists is in Why the fork.
- π API Documentation
- π Issue Tracker
- π± Demo app
- π§ Support
MIT Β© Iaptic