Skip to content

Installation

Requirements

  • Capacitor: 7.x. For the Capacitor 8 line — the current line, on @latest — see the current docs. For the Capacitor 5 line, install @nosslabs/iap@^5 (the 5.x releases) — see Migration.
  • Platform versions: iOS 15.0+ (StoreKit 2 requirement). Android API 21+ (Google Play Billing 7.x).
  • Node: 18+ for tooling.
  • Backend: any HTTP/JSON service you control (or a custom BackendAdapter for non-HTTP transports)

If your app needs to support iOS < 15, this library is not for you.

Install the package

bash
npm install @nosslabs/iap@^7

Pin the major. @nosslabs/iap@latest is now the 8.x (Capacitor 8) line, so a bare npm install @nosslabs/iap in a Capacitor 7 app installs a package whose peers require Capacitor 8. ^7 ranges resolve to this maintenance line, which is also reachable as the @latest-7 dist-tag. (For Capacitor 5, pin @nosslabs/iap@^5.)

On Capacitor 8?

The 8.x line is current, on @latest — use the current docs. The library's own API is identical on both lines; only the install command and the Capacitor peer range differ. See Migration.

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 7.x on the lts-v7 line.)

bash
npm install @capgo/native-purchases@lts-v7
npx cap sync

Pin the dist-tag rather than installing bare: npm's latest for that plugin points at its 8.x (Capacitor 8) line, so an unqualified npm install @capgo/native-purchases in a Capacitor 7 app pulls a version that 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:

bash
npm install @capacitor/core@^7 @capacitor/preferences@^7
npx cap sync

@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:

bash
npm install @capacitor/app@^7
npx cap sync

If 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() and iap.restorePurchases() reject with IAPError(PLATFORM_NOT_SUPPORTED)
  • iap.getProducts() returns []
  • All cached entitlement reads still work (entitlements are persisted via @capacitor/preferences which falls back to localStorage on 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:

xml
<!-- 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:

typescript
// 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

Released under the MIT License. Pairs with Attesto for server-side receipt validation.