Skip to content
Proofline

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 endUserId as the StoreKit appAccountToken (most purchase libraries expose it).
  • Android: pass it as obfuscatedAccountId in 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.

Next