stubkit docs

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

Configure

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

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

  1. User taps “Buy” → react-native-iap.requestPurchase()
  2. Store confirms → you get a receipt/token
  3. Call stubkit.syncPurchase() with the receipt
  4. Stubkit validates with Apple/Google and returns entitlements
  5. stubkit.isActive(‘pro’)true

Links