React Native / Expo
Install the Expo / React Native SDK, register installs, track events, and read attribution. Setup takes about 5 minutes.
Requirements
- React Native 0.71+
- React 18+
- iOS 14.0+ and Android 7.0+ (API 24+)
Install
npm
npm install postback-react-native@2.0.1# iOS onlycd ios && pod install
For Expo prebuild, add the config plugin to app.json and run npx expo prebuild. The plugin adds the required Android INTERNET / ACCESS_NETWORK_STATE / AD_ID permissions and does not add an iOS tracking-usage description.
Published on npm. Always use the latest version.
Configure
import { Platform } from 'react-native';import { Postback } from 'postback-react-native';// Call as early as possible. App.tsx, root layout, or _layout.tsx.await Postback.configure({apiKey: Platform.select({ios: 'pb_ios_live_xxxxx',android: 'pb_android_live_xxxxx',})!,});
Non-blocking. configure() resolves after local state is restored; install registration runs in the background on the native side. Lifecycle observers register automatically.
Track events
// Standard eventawait Postback.sendEvent('login');
// Revenue event. Currency must be exactly three ASCII letters.await Postback.sendEvent('purchase', null, {revenue: 9.99,currency: 'USD',});
// Custom event with parametersawait Postback.sendEvent('custom', 'level_complete', {level: 5,score: 1200,});
- Custom events require a trimmed, non-empty name of 1-255 UTF-16 code units with no U+0000 character. Invalid custom events are not queued.
- For standard event types, an invalid optional name is omitted and the event is still queued.
- Currency must be exactly three ASCII letters. Lowercase values are normalized to uppercase; an invalid currency field is omitted and the event is still queued.
Read attribution
Once install registration completes, the SDK caches the attribution result from the install response. Native iOS and Android expose synchronous getters; React Native and Flutter bridge calls are asynchronous.
const attr = await Postback.getAttribution();console.log(attr?.source); // "apple_ads", "tracking_link", or "organic"console.log(attr?.isAttributed); // booleanconsole.log(attr?.campaignName); // Campaign name when availableconsole.log(attr?.appleAds?.campaignId);console.log(attr?.link?.name);
Verify the connection
Send a test event to confirm end-to-end delivery. You should see it in the Postback dashboard within seconds.
const result = await Postback.sendTestEvent();console.log(result.success, result.message);
Reference
Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Your live API key (starts with pb_). |
| apiUrl | string | https://api.postback.sh | Override for staging or self-hosted environments. |
| enableAppleAdsAttribution | boolean | true | iOS only. Fetches Apple AdServices at install time. |
| customerUserId | string | null | null | Your internal user ID. Persists across launches and replays automatically if the first send fails. |
| autoTrackSessions | boolean | true | Fires session_start on configure() and on foreground, debounced to one event per 30 minutes. |
| autoRefreshAttribution | boolean | true | Refetches /v1/sdk/attribution on configure() and foreground transitions. |
| isDebug | boolean | false | Forces debug-level logging on the native side. |
| logLevel | 0 | 1 | 2 | 3 | 2 (WARN) | 0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR. |
Supported event types
session_startloginsign_upregisterpurchasesubscribestart_trialadd_payment_infoadd_to_cartadd_to_wishlistinitiate_checkoutview_contentview_itemsearchsharetutorial_completeachieve_levellevel_startlevel_completecustomUse custom with a name parameter for any event not in this list.
Attribution fields
| Field | Description |
|---|---|
| source | "apple_ads", "tracking_link", or "organic" |
| isAttributed | false for organic installs, true otherwise |
| matchType | Backend match method: apple_ads, click_id, gaid, ttclid, fbclid, gclid, gbraid, wbraid, ip_user_agent (Android only), or organic |
| campaignName | Signal Campaign name when available |
| link | Signal link object: id, name |
| appleAds | Apple AdServices payload: campaignId, adGroupId, keywordId, countryOrRegion, conversionType |
| utmSource | UTM source from the signal link |
| utmMedium | UTM medium from the signal link |
| utmCampaign | UTM campaign value from the signal link |
API reference
configure(config)
→ Promise<boolean>Initializes the SDK. Resolves true after local state is restored; install registration runs in the background.
await Postback.configure({ apiKey: '…' })
sendEvent(type, name?, params?)
→ Promise<boolean>Enqueues an event locally and schedules a flush. Custom events require a trimmed name of 1–255 UTF-16 code units.
await Postback.sendEvent('purchase', null, { revenue: 9.99, currency: 'USD' })
type is a string literal — see event types below.
flush()
→ Promise<void>Drains the queue immediately. Safe to call repeatedly.
await Postback.flush()
refreshAttribution()
→ Promise<AttributionResult | null>Fetches the latest attribution from the backend. Self-heals a 404 install_not_found by re-running install.
const attr = await Postback.refreshAttribution()
setCustomerUserId(id)
→ Promise<void>Updates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically.
await Postback.setCustomerUserId('user-123')
getPostbackId()
→ Promise<string | null>Returns the install ID, or null before install registration completes.
const id = await Postback.getPostbackId()
getAttribution()
→ Promise<AttributionResult | null>Returns the cached AttributionResult.
const attr = await Postback.getAttribution()
getAttributionParams()
→ Promise<Record<string, string>>Flat attribution/debug payload for custom integrations. For RevenueCat, set only the postbackId subscriber attribute.
const params = await Postback.getAttributionParams()
enableAppleAdsAttribution()
→ Promise<boolean>Re-enables Apple Ads at runtime on iOS. Returns false on Android.
await Postback.enableAppleAdsAttribution()
isInitialized()
→ Promise<boolean>True once configure() resolved.
await Postback.isInitialized()
isSdkDisabled()
→ Promise<boolean>True if a 401 or 403 permanently disabled the SDK.
await Postback.isSdkDisabled()
sendTestEvent()
→ Promise<{ success, message }>Posts a diagnostic event and resolves to (success, message).
const result = await Postback.sendTestEvent()
clearData()
→ Promise<void>Wipes local state and the event queue. Removes lifecycle observers.
await Postback.clearData()
destroy()
Removes native lifecycle observers without wiping data.
Postback.destroy()
Offline behavior
- Events that fail to send are queued in native storage (up to 100 events).
- The queue persists across app restarts.
- Queued events are retried when
configure()completes, when another event is sent, when lifecycle flushes run, or when you callflush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue.
Platform notes
- The JS layer is a thin bridge. Behavior matches the standalone native iOS and Android SDKs.
- On iOS, the package never requests ATT permission. IDFA is read only when the host app already has authorized ATT status; IDFV and app-scoped device context may be used for attribution.
- Host apps remain responsible for their own privacy notices, App Store answers, and any permissions required by their complete data practices.
- On iOS, AdServices runs on iOS 14.3+. Older OS versions skip Apple Ads attribution silently.
- On Android, GAID is read off the main thread, honoring Limit Ad Tracking and dropping the all-zero advertising ID.
- Events persist to native storage (UserDefaults on iOS, SharedPreferences on Android) and survive app restarts. Maximum queue size is 100 events.
- On iOS, URLSession requests fail fast when connectivity is unavailable. Events stay in the persistent SDK queue and retry on lifecycle flushes, the next sendEvent(), or flush().
- On Expo, the bundled config plugin adds Android INTERNET, ACCESS_NETWORK_STATE, and AD_ID permissions. It does not add NSUserTrackingUsageDescription on iOS.
Next steps
Troubleshooting
| Problem | What to try |
|---|---|
| getPostbackId() returns null | configure() resolves before install registration finishes on the native side. Retry briefly, or read the value after the first event has been sent. |
| Events do not appear in dashboard | Confirm the API key starts with pb_. Call sendTestEvent() and inspect the returned message. |
| SDK disabled (isSdkDisabled returns true) | The API returned 401 or 403. Call clearData(), then configure() with a valid key. |
| Apple Ads attribution not detected | AdServices requires a real device (not the simulator). Confirm enableAppleAdsAttribution is true and that the test build is signed with a real provisioning profile. |
| pod install fails after adding the package | Delete ios/Podfile.lock and ios/Pods, then run pod install --repo-update. |
| Android build cannot find AD_ID | The package's manifest declares com.google.android.gms.permission.AD_ID and is merged at build time. If you target an app that cannot use it, remove with tools:node="remove". |