React Native SDK
Complete reference for the AppRefer React Native SDK. @apprefer/react-native-sdk is a pure TypeScript package with zero native modules — it layers on top of React Native's built-in Platform and Linking APIs and persists state via AsyncStorage.
Installation#
The SDK is published to npm. Install it along with its single peer dependency, @react-native-async-storage/async-storage:
npm install @apprefer/react-native-sdk @react-native-async-storage/async-storage
# or
yarn add @apprefer/react-native-sdk @react-native-async-storage/async-storageAlternatively, install the latest commit straight from GitHub:
npm install github:AppAgentic/apprefer-react-native-sdkExpo projects
npm ls @react-native-async-storage/async-storage before installing it a second time. The AppRefer SDK itself is a pure JS package, so it works in bare React Native, Expo dev builds, and Expo Go (linking requires a native build, which Expo Go supports via the built-in expo-linking).Native autolinking & iOS pods#
AppRefer itself has no native code, so nothing to link. AsyncStorage does have a native module — on React Native 0.60+ it is autolinked, you only need to install the CocoaPod:
cd ios && pod install && cd ..Permissions#
The SDK does not declare any Android or iOS permissions on its own. Network access comes from the host app's default INTERNET permission (Android) and App Transport Security defaults (iOS). It does not require com.google.android.gms.permission.AD_ID — no Play Data Safety disclosure is triggered by AppRefer.
Inherited native attribution signals#
When a user clicks a trk.apprefer.com/api/c/<linkId> link and installs the app, the click ID travels through platform-native channels that the React Native SDK automatically picks up:
- iOS — AdServices / Apple Search Ads. The tracking server performs server-side AdServices token resolution for Apple Search Ads campaigns. No client-side setup required.
- Android — Google Play Install Referrer. The server parses the referrer string at
configure()time via the device fingerprint, extractinggclid,fbclid,ar_click_idand theutm_*params. - Both platforms — IP/UA fingerprint. If deterministic signals miss, the backend probabilistically matches the install to the most recent click from the same IP + User-Agent within a short window.
Quickstart#
Call AppRefer.configure() once at app startup — typically from the root component's useEffect or your Expo _layout.tsx.
import { useEffect } from 'react';
import { AppRefer } from '@apprefer/react-native-sdk';
export default function App() {
useEffect(() => {
(async () => {
const attribution = await AppRefer.configure({
apiKey: 'pk_live_your_key_here', // pk_test_ during development
debug: __DEV__,
});
if (attribution) {
console.log('Network:', attribution.network);
console.log('Match type:', attribution.matchType);
}
})();
}, []);
return /* ...your app */ null;
}API Reference#
The SDK never crashes the host app
configure(), it returns without throwing (you'll see a __DEV__ warning in dev builds).AppRefer.configure(config)#
Initialize the SDK and resolve attribution. On first launch this sends a single network request; subsequent calls return the cached result with no network overhead.
| Field | Type | Default | Description |
|---|---|---|---|
apiKey | string | required | Your SDK key (pk_live_... or pk_test_...) |
userId | string? | undefined | Optional RevenueCat user ID to associate with the attribution at init time |
debug | boolean | false | Enable verbose console logging |
logLevel | number | 1 | 0 = none, 1 = errors, 2 = warnings, 3 = verbose |
| Details | |
|---|---|
| Signature | static configure(config: AppReferConfig): Promise<Attribution | null> |
| Returns | Attribution | null — resolved attribution, or null for organic installs / kill-switch / first-run failure |
| Throws | Never |
AppRefer.trackEvent(eventName, options?)#
Send a custom event to AppRefer. Purchases are handled automatically via RevenueCat webhooks — use trackEvent for signup, tutorial completion, lead events, etc.
| Parameter | Type | Default | Description |
|---|---|---|---|
eventName | string | required | Event name (e.g., "signup", "tutorial_complete") |
options.properties | Record<string, unknown>? | undefined | Arbitrary key-value metadata |
options.revenue | number? | undefined | Revenue amount (e.g., 9.99) |
options.currency | string? | undefined | ISO 4217 currency code (e.g., "USD") |
await AppRefer.trackEvent('tutorial_complete', {
properties: { level: 3, time_spent: 42 },
});
// With revenue
await AppRefer.trackEvent('lead_qualified', {
revenue: 9.99,
currency: 'USD',
});AppRefer.setAdvancedMatching(options)#
Send hashed PII to improve Meta CAPI match rates. All values are SHA256-hashed on-device before being sent — the server never receives plaintext PII.
| Field | Type | Default | Description |
|---|---|---|---|
email | string? | undefined | User's email address |
phone | string? | undefined | Phone number in E.164 format |
firstName | string? | undefined | User's first name |
lastName | string? | undefined | User's last name |
dateOfBirth | string? | undefined | Date of birth (YYYYMMDD) |
await AppRefer.setAdvancedMatching({
email: 'user@example.com',
phone: '+15551234567',
firstName: 'Jane',
lastName: 'Doe',
});AppRefer.setUserId(userId)#
Associate a user ID with the device's attribution. Typically called with the RevenueCat app user ID so purchase webhooks can be matched back to the attributed device.
appreferId must be set on RevenueCat FIRST
appreferId subscriber attribute on RevenueCat. This is how AppRefer links RevenueCat webhook events back to the attributed device. Without it, purchase events cannot be forwarded to ad networks.import Purchases from 'react-native-purchases';
import { AppRefer } from '@apprefer/react-native-sdk';
await AppRefer.configure({ apiKey: 'pk_live_...' });
// REQUIRED: link AppRefer device ID to RevenueCat
const deviceId = await AppRefer.getDeviceId();
if (deviceId) {
Purchases.setAttributes({ appreferId: deviceId });
}
// Optional: mirror RevenueCat user ID back to AppRefer
const info = await Purchases.getCustomerInfo();
await AppRefer.setUserId(info.originalAppUserId);AppRefer.getAttribution()#
Returns the cached attribution from the last configure() call. Synchronous — no await needed.
| Details | |
|---|---|
| Signature | static getAttribution(): Attribution | null |
| Returns | Attribution | null — cached attribution, or null if configure() has not completed or the install is organic |
AppRefer.getDeviceId()#
Returns the stable device ID generated by AppRefer on first run and persisted in AsyncStorage. Use this as the value of the appreferId RevenueCat subscriber attribute.
| Details | |
|---|---|
| Signature | static getDeviceId(): Promise<string | null> |
| Returns | string | null — device UUID, or null before configure() has run |
AppReferDeepLinks — click ID extraction#
The SDK automatically reads the cold-start launch URL during configure() and extracts any ar_click_id query parameter. For warm-start deep links (e.g. a link tapped while the app is already running), the exported AppReferDeepLinks helper exposes a static extractClickId so you can parse a click ID out of any URL your existing linking code receives:
import { Linking } from 'react-native';
import { AppReferDeepLinks } from '@apprefer/react-native-sdk';
Linking.addEventListener('url', ({ url }) => {
const clickId = AppReferDeepLinks.extractClickId(url);
if (clickId) {
// Your app can now route based on the click ID.
// The cold-start click ID was already captured during configure().
}
});Kill switch
configure() response turns the SDK off — all subsequent trackEvent and setAdvancedMatching calls become no-ops until you re-enable it. No app release required.Attribution Model#
The Attribution type returned by configure() contains the following properties:
| Property | Type | Description |
|---|---|---|
network | string | Ad network (e.g., "meta", "google", "tiktok", "apple_search_ads", "organic") |
matchType | string | How attribution was determined ("click_id", "adservices", "referrer", "organic") |
campaign | string? | Campaign name (compat alias) |
campaignId | string? | Campaign ID from ad network |
campaignName | string? | Campaign name from ad network |
adGroupId | string? | Ad group / ad set ID |
adId | string? | Ad creative ID |
keyword | string? | Search ad keyword (when applicable) |
fbclid | string? | Meta click ID (if present) |
gclid | string? | Google click ID (if present) |
ttclid | string? | TikTok click ID (if present) |
queryParams | Record<string, unknown> | All query parameters from the tracking link |
customData | Record<string, unknown> | Custom data attached to the tracking link |
createdAt | string | ISO 8601 timestamp the attribution was resolved |
Full Integration Example#
A complete integration wiring AppRefer to RevenueCat, including attribution resolution, user ID linking, and advanced matching after signup:
import { useEffect } from 'react';
import Purchases from 'react-native-purchases';
import { AppRefer } from '@apprefer/react-native-sdk';
export default function App() {
useEffect(() => {
(async () => {
// Configure RevenueCat
Purchases.configure({ apiKey: 'rc_public_key' });
// 1. Initialize AppRefer and resolve attribution
const attribution = await AppRefer.configure({
apiKey: 'pk_live_your_key_here',
debug: __DEV__,
});
console.log('Network:', attribution?.network ?? 'organic');
// 2. CRITICAL: link AppRefer device ID to RevenueCat
// Without this, purchases CANNOT be attributed to ad campaigns.
const deviceId = await AppRefer.getDeviceId();
if (deviceId) {
Purchases.setAttributes({ appreferId: deviceId });
}
// 3. Mirror the RevenueCat user ID back to AppRefer
const info = await Purchases.getCustomerInfo();
await AppRefer.setUserId(info.originalAppUserId);
})();
}, []);
return /* ...your app */ null;
}
// Later, after the user signs up...
export async function onUserSignup(email: string, firstName: string) {
// 4. Advanced matching (hashed on-device)
await AppRefer.setAdvancedMatching({ email, firstName });
// 5. Track the signup event
await AppRefer.trackEvent('signup');
}Best Practices#
- Call
configure()as early as possible — ideally from your rootAppcomponent or Expo_layout.tsx. The sooner it runs, the tighter the attribution window. - Always set
appreferIdon RevenueCat immediately afterconfigure(). This is how RevenueCat purchase webhooks are matched back to AppRefer attributions. Without it, purchases cannot be attributed. - Call
setAdvancedMatching()once per user session — right after signup or login — to lift Meta CAPI match rates. - Don't track purchases with
trackEvent(). Revenue events are forwarded automatically from RevenueCat webhooks. UsetrackEvent()for signup, tutorial completion, onboarding milestones, etc. - Use
pk_test_keys in development. Sandbox events are isolated from production and never forwarded to ad networks. Switch topk_live_for release builds. - Set
debug: __DEV__so verbose logs appear only in development builds.
Troubleshooting#
- Metro bundler doesn't pick up the SDK. Reset the cache with
npx react-native start --reset-cache(orexpo start -con Expo). - iOS build fails after install. Re-run
cd ios && pod install— AsyncStorage is a native module and needs its pod re-generated. - Android build fails with minSdk error. Ensure your app's
minSdkVersionis at least 21. This is React Native's own baseline — AppRefer does not raise it further. configure()returnsnullon every launch. Setdebug: trueand check the Debugger tab in the AppRefer dashboard to confirm the configure request is arriving — organic installs correctly resolve tonull.
Requirements#
| Requirement | Minimum Version |
|---|---|
| React Native | 0.70+ |
| iOS | 14.0+ |
| Android | API 21 (Android 5.0 Lollipop) |
| TypeScript | 5.0+ (optional — works in plain JS too) |
| Peer dependency | @react-native-async-storage/async-storage 1.17+ |
Source code