Quickstart · React Native
React Native and Expo quickstart
The TypeScript SDK has no dependencies. The React Native adapter takes the modules you already
use (Linking, AsyncStorage and, on Android, an Install Referrer bridge) so it never imports
react-native itself.
You need your app’s publishable key from App settings → Publishable key and your Proofline
platform URL, https://app.proofline.link. Each app has one publishable key (pk_live_…; a local development
server issues pk_test_…): use it in debug and release builds alike.
1. Start the adapter at launch
import { Linking, Platform } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createReactNativeAdapter } from '@proofline/sdk-js/rn';
const proofline = createReactNativeAdapter({
linking: Linking,
asyncStorage: AsyncStorage,
// Android only: any bridge with getInstallReferrer(): Promise<string | null>
installReferrer: Platform.OS === 'android' ? installReferrerBridge : undefined,
platform: Platform.OS === 'ios' ? 'ios' : 'android',
});
await proofline.start({
appKey: 'pk_live_…',
// Your Proofline platform: every SDK request goes here.
baseUrl: 'https://app.proofline.link',
});Always pass baseUrl: it is your Proofline platform, https://app.proofline.link, and every SDK request goes
there. Public calls never throw, so with a wrong or missing host nothing fails visibly; the SDK
just records nothing. Pass debug: true while you integrate to log failed and retried requests
with console.warn.
start configures the SDK, reads the URL that opened the app, subscribes to later url
events, and passes the Play Install Referrer once after install. The offline queue lives in
AsyncStorage and retries with backoff; every event has an idempotent ID.
2. Identify, then pass the ID to the store
import { identify } from '@proofline/sdk-js/rn';
const endUserId = await identify(user.id); // null when offline; never throws
- iOS: pass
endUserIdas the StoreKitappAccountToken(most purchase libraries expose it). - Android: pass it as
obfuscatedAccountIdin Play Billing.
3. Codes on your paywall
import { submitCode } from '@proofline/sdk-js/rn';
const result = await submitCode(code, 'typed');
if (result.status === 'accepted' && result.redemptionUrl) {
await Linking.openURL(result.redemptionUrl); // Apple's offer-code redemption
}
Other statuses are unknown_code, expired, exhausted, revoked and error. Public calls
never throw.
4. RevenueCat
import Purchases from 'react-native-purchases';
import { syncToRevenueCat } from '@proofline/sdk-js/rn';
await syncToRevenueCat(Purchases);
This writes proofline_end_user_id, proofline_creator_id, proofline_creator_handle,
proofline_program_id, proofline_tier and proofline_code as subscriber attributes.
5. Paywall copy (optional)
import { currentAttribution } from '@proofline/sdk-js/rn';
const a = await currentAttribution();
const label = a ? `${a.creator.name}'s ${a.offerLabel ?? 'offer'}` : null;
Expo
The adapter works in Expo’s managed workflow with expo-linking (pass it as linking). An Expo
config plugin that sets up associated domains and app links is planned.