Installation
Requirements
- Capacitor: 8.x. For the Capacitor 7 line, install
@nosslabs/iap@^7— see the v7 docs. For the Capacitor 5 line, install@nosslabs/iap@^5— see the v5 docs and Migration. - Platform versions: iOS 15.0+ (StoreKit 2 requirement). Android API 24+ (Capacitor 8's minimum; the line ships Google Play Billing 8.x).
- Node: 22+ (required by Capacitor 8).
- Backend: any HTTP/JSON service you control (or a custom
BackendAdapterfor non-HTTP transports)
If your app needs to support iOS < 15, this library is not for you.
Install the package
npm install @nosslabs/iap(@nosslabs/iap@latest is the 8.x (Capacitor 8) line, also reachable as @latest-8. For Capacitor 7, pin @nosslabs/iap@^7 — ^7 ranges resolve to the maintenance 7.x line, not 8.x. For Capacitor 5, pin @nosslabs/iap@^5.)
Still on Capacitor 7?
The 7.x line stays supported on @latest-7:
npm install @nosslabs/iap@^7 @capgo/native-purchases@lts-v7Below, use @capgo/native-purchases@lts-v7 in place of the bare plugin install, and @capacitor/*@^7 in place of @capacitor/*@^8 — the library's own API is identical on both lines. Full instructions live in the v7 docs.
Install the native plugin
@nosslabs/iap wraps @capgo/native-purchases — a free, MIT-licensed, StoreKit 2 / Google Play Billing plugin built as a first-class Capacitor plugin. (Play Billing 8.x on the 8.x line; 7.x on the lts-v7 line.)
npm install @capgo/native-purchases
npx cap syncOn Capacitor 8 the plugin's default latest tag is correct. On Capacitor 7, pin @lts-v7 instead — latest points at the 8.x line, which requires Capacitor 8.
npx cap sync is required so the iOS and Android native projects pick up the plugin code. Re-run it any time you add/update native dependencies.
Don't skip cap sync
A common cause of purchases silently failing (or isAvailable() returning false) is forgetting npx cap sync after installing @capgo/native-purchases. The plugin's native source files don't get linked otherwise.
Install Capacitor peer dependencies
If you don't already have these installed, add them — matching your Capacitor major:
npm install @capacitor/core@^8 @capacitor/preferences@^8
npx cap sync(On the 7.x line, use @^7 for both — see the v7 docs.)
@capacitor/preferences is what the library uses for the entitlement cache and unfinished-transaction storage. It's backed by NSUserDefaults on iOS, SharedPreferences on Android, and localStorage on web.
Optional: app-resume listener
By default, @nosslabs/iap automatically calls iap.refresh() whenever the app returns from background. This catches subscription changes that happened server-side (renewals, billing retries, refunds via Attesto webhooks) without the user pulling-to-refresh.
To enable it, install @capacitor/app:
npm install @capacitor/app
npx cap syncIf you don't want this behavior, set options.refreshOnResume: false in your config and skip the install.
Optional peer dep
@capacitor/app is declared as peerDependenciesMeta.optional: true in @nosslabs/iap's package.json. npm won't complain if you skip it. The library detects its absence at runtime and logs a debug-level note instead of crashing.
Web platform note
@capgo/native-purchases is iOS/Android only. On web:
iap.purchase()andiap.restorePurchases()reject withIAPError(PLATFORM_NOT_SUPPORTED)iap.getProducts()returns[]- All cached entitlement reads still work (entitlements are persisted via
@capacitor/preferenceswhich falls back tolocalStorageon web) iap.refresh()works (it's a plain HTTP call)
This means you can develop your UI in a browser without crashes, and entitlement-gated UI will render correctly based on cached state from a previous mobile session — useful for development workflows.
Android MainActivity launch mode
Set your MainActivity's launch mode to standard or singleTop:
<!-- android/app/src/main/AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:launchMode="standard"
...
>Otherwise the purchase flow can be cancelled when the user backgrounds the app to verify a card in their banking app — Google Play Billing requires the activity to be the foreground task when the purchase resumes.
Verify the install
Create a tiny script to confirm everything resolves:
// scripts/check-iap-install.ts
import { createIAP } from '@nosslabs/iap';
const iap = createIAP({
products: [{ id: 'test', type: 'product' }],
backend: {
baseUrl: 'https://example.com',
endpoints: {
verifyApple: '/x',
verifyGoogle: '/x',
entitlements: '/x',
restore: '/x',
},
getAuthHeaders: () => ({}),
},
});
console.log('createIAP factory works.');Run with tsx scripts/check-iap-install.ts or similar. No errors → install is healthy.
Next
- Configuration — full options reference
- Getting started — first purchase walkthrough