Quickstart · React Native / Expo
React Native / Expo
@stubkit/js is your SDK — no separate React Native package needed. It uses pure fetch with zero DOM or Node.js dependencies, so it works in React Native and Expo out of the box.
Install
npx expo install @stubkit/js
# or: npm install @stubkit/jsConfigure
// App.tsx or a shared lib/stubkit.ts
import { StubkitClient } from '@stubkit/js';
export const stubkit = new StubkitClient({
appId: 'your-app-id',
publishableKey: 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxx',
getAuthToken: async () => {
// Return your tenant JWT — Supabase, Clerk, Firebase, Auth0, custom...
const session = await auth.getSession();
return session?.access_token ?? '';
},
});Check entitlement
const isPro = await stubkit.isActive(userId, 'pro');
if (isPro) {
// Unlock pro features
}Fetch paywall config
const offering = await stubkit.getOffering('default');
// offering.title, offering.features, offering.products[].productId
// Use react-native-iap or expo-in-app-purchases to show native pricesSync purchase (after react-native-iap)
import { requestPurchase } from 'react-native-iap';
// After a successful purchase:
const entitlements = await stubkit.syncPurchase({
userId: currentUserId,
platform: Platform.OS === 'ios' ? 'ios' : 'android',
productId: 'com.yourapp.pro.monthly',
receipt: purchase.transactionReceipt, // iOS
// or: receipt: purchase.purchaseToken // Android
transactionId: purchase.transactionId,
});Track events (get paywall suggestion)
const result = await stubkit.track(
'hit_export_limit',
{ count: 5, plan: 'free' },
{ userId: currentUserId },
);
if (result.showPaywall) {
navigation.navigate('Paywall', { offering: result.showPaywall });
}React hooks
The @stubkit/js/react subpath exports hooks that work in React Native:
import { StubkitProvider, useIsActive, useOffering } from '@stubkit/js/react';
function App() {
return (
<StubkitProvider
appId="your-app-id"
publishableKey="pk_live_xxx"
getAuthToken={getToken}
userId={currentUserId}
>
<HomeScreen />
</StubkitProvider>
);
}
function HomeScreen() {
const isPro = useIsActive('pro');
const { offering, isLoading } = useOffering('default');
if (!isPro && !isLoading && offering) {
return <PaywallScreen offering={offering} />;
}
return <ProContent />;
}Expo compatibility
- SDK 50+ (React Native 0.73+) — fully supported.
- Expo Go — entitlement checks and paywalls work. IAP requires a dev build.
- EAS Build — works out of the box, no native modules in
@stubkit/js.
In-app purchases
Stubkit is not a replacement for react-native-iap or expo-in-app-purchases. Those handle the native store transaction. Stubkit validates the receipt server-side and tells you whether the user is Pro. Typical flow:
- User taps “Buy” →
react-native-iap.requestPurchase() - Store confirms → you get a receipt/token
- Call
stubkit.syncPurchase()with the receipt - Stubkit validates with Apple/Google and returns entitlements
stubkit.isActive(‘pro’)→true