React Native SDK
Add the pure JavaScript RevenueHog SDK to a React Native or Expo app, including Expo Go, to attribute purchases, identify users and serve paywall SKUs.
@revenuehog/react-native is pure TypeScript with no native code, so it works in Expo Go. It has zero runtime dependencies and detects optional modules at runtime.
Install
The package is not published to npm yet. Build it from a checkout of the SDK repository (dist/ is not committed) and install it as a local file dependency:
git clone https://github.com/Parra-Inc/revenue-hog-sdks
cd revenue-hog-sdks/react-native && npm install && npm run build
cd <your app> && npm install file:../revenue-hog-sdks/react-nativeOptional modules, detected automatically and never required:
| Module | Used for |
|---|---|
@react-native-async-storage/async-storage | Persists the anonymous ID, install ID, paywall cache and offline queue across relaunches. Recommended for production. |
expo-application or react-native-device-info | Detects the bundle ID. react-native-device-info also provides the device model. |
react-native-iap | Automatic purchase attribution. |
Without AsyncStorage the SDK falls back to in-memory storage: the anonymous ID does not survive a relaunch. That is fine in development.
Quickstart
import RevenueHog from '@revenuehog/react-native';
RevenueHog.configure();await RevenueHog.identify('user_42'); // after login
await RevenueHog.reset(); // on logoutHow auth works
There is no API key and no attestation yet. Requests carry no Authorization header; RevenueHog resolves them by bundle ID and labels the data unverified. One exception: on iOS, a purchase attributed with a StoreKit 2 signed transaction (jws) is verified against Apple's signature, so that purchase link is trusted. See Authentication.
Attributing purchases
Automatic. When react-native-iap is installed and autoAttribution is not false, the SDK hooks purchaseUpdatedListener and attributes every purchase. It uses originalTransactionIdentifierIOS, falling back to transactionId, and passes the signed transaction from jwsRepresentationIos, jwsRepresentationIOS or verificationResultIOS when the value looks like a JWS (three dot-separated segments).
Manual. Call attributePurchase from your own listener:
import { purchaseUpdatedListener } from 'react-native-iap';
purchaseUpdatedListener((purchase) => {
RevenueHog.attributePurchase({
originalTransactionId:
purchase.originalTransactionIdentifierIOS ?? purchase.transactionId!,
productId: purchase.productId,
jws: purchase.jwsRepresentationIos,
});
});// expo-in-app-purchases
setPurchaseListener(({ results }) => {
for (const p of results ?? []) {
RevenueHog.attributePurchase({
originalTransactionId: p.originalOrderId ?? p.orderId,
productId: p.productId,
});
}
});On Android, pass the Play purchase token as originalTransactionId.
API reference
Every method returns a promise that resolves normally, even on failure.
| Call | What it does |
|---|---|
RevenueHog.configure(config?) | Sets up the SDK, flushes the queue and hooks react-native-iap when enabled. Never throws. |
RevenueHog.identify(userId) | Links the anonymous ID, and everything reported under it, to your user ID. |
RevenueHog.setAttributes(attrs) | Attaches a flat Record<string, string> to the user's profile. |
RevenueHog.attributePurchase({ originalTransactionId, productId?, jws? }) | Links a purchase to the current user. |
RevenueHog.reset() | Forgets the user on logout and issues a fresh anonymous ID. |
RevenueHog.flush() | Retries the offline queue, for example when connectivity returns. |
RevenueHog.paywall(entitlement, fallback, options?) | Resolves the ordered SKU list. Never rejects. See Paywall. |
RevenueHog.paywallShown(paywall, rendered) | Reports that the paywall appeared, with the rendered product IDs. |
The module also exports HogClient, memoryStorage and the types AttributePurchaseInput, LogLevel, Paywall, PaywallOptions, PaywallSku, PaywallSkuKind, RevenueHogConfig and StorageAdapter.
RevenueHogConfig
RevenueHog.configure({
baseUrl: 'https://hog.internal.example',
bundleId: 'com.your.app',
autoAttribution: true,
storage: myStorageAdapter,
logLevel: 'warn',
storeEnvironment: 'Sandbox',
});Prop
Type
Paywall
interface Paywall {
entitlement: string;
skus: { productId: string; kind: 'subscription' | 'iap' | 'unknown' }[];
productIds: string[];
experimentId?: string;
variantKey?: string;
isFallback: boolean;
}const paywall = await RevenueHog.paywall('pro', ['app_pro_annual', 'app_pro_monthly']);
const products = await getSubscriptions({ skus: paywall.productIds });
const ordered = paywall.productIds
.map((id) => products.find((p) => p.productId === id))
.filter(Boolean);
// after render:
RevenueHog.paywallShown(paywall, ordered.map((p) => p.productId));options.forceVariant previews a variant for QA (see Experiments). The fetch deadline is 2.5 seconds.
Install ID stickiness
The install ID is a UUID persisted in your storage adapter. AsyncStorage survives logout but not reinstall, so experiment assignment is less sticky than on iOS, where the Keychain keeps the ID across reinstalls.
Behavior notes
- Failed requests (network,
429,5xx) retry up to 3 times with 500 ms then 1 s backoff, then queue (cap 100). - Other non-2xx responses are logged and dropped.
- The SDK skips transactions already reported for the current user.
Troubleshooting
Pass bundleId to configure, or install expo-application or react-native-device-info.
Set logLevel: 'debug' and check that the bundle ID matches an app in your workspace.
Expected for this SDK today. Purchases sent with jws are still transaction-verified.
Related
Last updated on
Android SDK
Add the RevenueHog Kotlin SDK to an Android app to identify users, attach attributes, map Play purchases to users and serve paywall SKUs from the dashboard.
Attribution
How RevenueHog links store purchases to your own user IDs with identify and attribute, how anonymous IDs re-point after login, and the Apple Ads token.