Respectlytics Respect lytics
Menu
React Native In-app purchase Privacy-first

How to track in-app purchases in React Native without personal data

In-app purchase is the bread-and-butter event of mobile games and content apps. Most analytics SDKs treat it as a per-user revenue event with SKU, price, currency, and transaction ID. Respectlytics helps developers avoid collecting personal data in the first place: in React Native, IAP is one named event when a transaction succeeds, with no metadata. Revenue accounting lives in your billing system. Below: the React Native pattern, the difference between consumable and non-consumable purchases, and the metadata trade-offs.

Wire the call into the success branch of your StoreKit / Billing transaction handler. Use distinct event names per purchase category if you want to differentiate consumables from non-consumables (iap_consumable, iap_nonconsumable). Don't pass the SKU, price, or transaction ID.

Install the React Native SDK

bash Respectlytics
npm install @respectlytics/react-native
# or
yarn add @respectlytics/react-native

JavaScript-only — no native modules, no auto-linking, no New Architecture migration concerns. Bundle size: ~14KB minified+gzipped. Works in any Expo project (managed or bare) without expo prebuild.

Initialize Respectlytics in React Native

js Respectlytics
// App.tsx (or App.js)
import { useEffect } from 'react';
import Respectlytics from '@respectlytics/react-native';

export default function App() {
  useEffect(() => {
    Respectlytics.configure({ appKey: '<YOUR_APP_KEY>' });
  }, []);
  return <YourApp />;
}

Initialize once in your top-level component. No native config; no Info.plist or AndroidManifest changes. The SDK is Hermes- and JSC-compatible.

Track the event in React Native

js Respectlytics
import Respectlytics from '@respectlytics/react-native';
import { useIAP } from 'react-native-iap';
import { useEffect } from 'react';

const CONSUMABLE_SKUS = new Set(['gold_pack_small', 'gold_pack_large']);

export function useIAPTracking() {
  const { currentPurchase, finishTransaction } = useIAP();
  useEffect(() => {
    if (!currentPurchase?.transactionReceipt) return;
    const isConsumable = CONSUMABLE_SKUS.has(currentPurchase.productId);
    Respectlytics.track(isConsumable ? 'iap_consumable' : 'iap_nonconsumable');
    finishTransaction({ purchase: currentPurchase, isConsumable });
  }, [currentPurchase, finishTransaction]);
}

Maintain the SKU → consumable mapping app-side. react-native-iap's finishTransaction requires isConsumable anyway, so the lookup is reusable.

Privacy & implementation notes

Consumables (a single in-game gold pack) and non-consumables (a one-time premium upgrade) have very different product implications: consumables drive ARPU directly, non-consumables drive long-term retention. Mixing them under one iap event hides the most useful breakdown.

Always finish the transaction with the platform billing API after firing the analytics event — not before. If your track call were to throw (it doesn't, but defensively), you'd want the platform to keep its retry behavior. Respectlytics's track is a fire-and-forget call into a RAM queue; it never blocks transaction completion.

The React Native SDK is JavaScript-only — no Objective-C/Swift bridging on iOS, no Java/Kotlin bridging on Android. Side effects: no react-native link, no auto-linking, no New Architecture migration concerns, no platform-channel exception surfaces. Trade-off: no access to platform-only metadata (which we don't want to collect anyway).

Works in Expo managed workflow without expo prebuild. No config plugin is required. EAS Build users: nothing to configure. This is the smoothest integration path on RN — most analytics SDKs require ejecting from managed.

How this compares to other analytics SDKs

In-app purchase eventFirebase AnalyticsMixpanelRespectlytics
SKU storedRecommendedRecommendedUse distinct event_name
Price / currency storedRecommendedRecommendedRejected by API
Transaction ID storedYesYesRejected by API
Per-user spend totalYesYesUse billing system
Purchase *rate* by country / platformYesYesYes (default)

Frequently asked questions

How do we differentiate consumables from non-consumables?

Distinct event names: iap_consumable, iap_nonconsumable, optionally iap_subscription for subscriptions. Don't embed the type as a parameter — the API rejects parameters.

What about lifetime spend per user?

Out of scope for Respectlytics. Your billing system or RevenueCat already computes lifetime spend per user, with authoritative timestamps and refund-aware totals. Asking your product analytics to do this duplicates a system of record and produces drift.

Do we differentiate purchases by SKU at all?

Only if a SKU breakdown is genuinely actionable for product decisions, and only via distinct event names: iap_gold_pack, iap_starter_bundle. Keep the set small — under 10 SKUs is fine; past that, bucket the long tail.

Should we fire on purchase initiation or completion?

Completion. Initiation-fire inflates the event count with abandoned platform billing prompts. The transaction observer's .purchased state is the right hook.

Related guides

Track what matters. Collect nothing you don't.

Five-field event schema, RAM-only event queue, no IDFA, no AAID, no persistent user IDs. Helps developers avoid collecting personal data in the first place.