ReflectDocs
Browse docsOverview
React Native SDK

React Native SDK

Reflect SDK for React Native — a thin JS + native bridge over the shared ReflectCore engine. Mobile attribution, event tracking, deep linking, and SKAN for iOS and Android.

v2.0.0 — thin wrapper over the shared native core
As of v2.0.0 the SDK runs on Reflect's shared ReflectCore engine — the same Kotlin (reflect-android) and Swift (reflect-ios) core the Flutter and Unity SDKs use. All logic (durable on-disk queue, HMAC-signed ingest, batching, response-driven retry, device signals, deferred deep links, attribution, SKAN, ATT) lives in the core; this package only translates the RN bridge onto it. v1 was a standalone re-implementation that posted unsigned events — v2 is a breaking native rewrite, but the public JS API stays backward-compatible and gains new methods. Your install_uuid is preserved across the upgrade, so it is not counted as a reinstall.

Installation

Install from GitHub, pinned to a tagged release — this package is not published to the public npm registry:

npm install github:bablu147/reflect-sdk-react-native#v2.0.0

This is an autolinked native module. On iOS, install the pods — this pulls the shared ReflectCore pod:

cd ios && pod install

On Android, the shared core is pulled from JitPack. React Native 0.73+ resolves dependencies per-project, so add the repository to an allprojects block in your app's root android/build.gradle. A settings.gradle dependencyResolutionManagement block is ignored on RN 0.73+ and the build will fail to resolve the core:

// android/build.gradle — after the buildscript { } block
allprojects {
  repositories {
    maven { url 'https://jitpack.io' }   // com.github.bablu147:reflect-android
  }
}

Then rebuild the native app — a Metro/JS reload is not enough for a newly-added native module:

npx react-native run-android

The Android AAR brings its transitive dependencies (Play Install Referrer, App Set ID, ads-identifier) and R8 keep-rules automatically. If the ReflectCore pod is not yet on CocoaPods trunk, add it to your ios/Podfile:

pod 'ReflectCore', :git => 'https://github.com/bablu147/reflect-ios.git', :tag => '1.0.0'

Requirements

  • React Native >=0.71.0
  • React >=18.0.0
  • iOS 12+, Android (Google Play Services)
  • Supports both Old Architecture (Bridge) and New Architecture (legacy bridge via the interop layer)

Quick start

import { Reflect } from '@reflect-sdk/react-native';

// Initialize once at app startup
Reflect.initialize({
  appKey:     'app_live_...',
  companyKey: 'co_live_...',
  baseUrl:    'https://api.reflect.cloud',
  // signingSecret: 'sec_...',  // optional — HMAC-signs ingest + surfaces attribution
});

With a signingSecret set, every event batch is HMAC-signed and posted to the authenticated /event endpoint; without one the SDK falls back to the unsigned /event/batch path. An app_open event is sent automatically on init.

API reference

MethodDescription
Reflect.initialize(config)Initialize the SDK
Reflect.trackEvent(name, props?)Track event with optional properties
Reflect.trackRevenue(params)Track revenue event
Reflect.trackPurchase(params)Track purchase with optional receipt data
Reflect.trackSubscription(params)Track subscription event
Reflect.verifyPurchase(params)Verify a receipt server-side and return a typed result
Reflect.trackAdRevenue(params)Track mediated ad revenue (fires ad_impression)
Reflect.setUserId(userId)Set user ID
Reflect.clearUserId()Clear user ID
Reflect.setEmail(email)Attach the user's RAW email to future events (server hashes it; consent-gated) — enables email attribution
Reflect.clearEmail()Clear the stored email (e.g. on logout)
Reflect.setUserProperties(props)Set user-level properties
Reflect.setGlobalProperty(key, val)Set a property merged into every event
Reflect.unsetGlobalProperty(key)Remove a global property
Reflect.clearGlobalProperties()Remove all global properties
Reflect.setPartnerParameter(key, val)Set a global partner parameter forwarded to integrations
Reflect.setPartnerSharing(map)Per-partner third-party-sharing overrides
Reflect.setThirdPartySharing(enabled)Opt in/out of partner data sharing
Reflect.setAdvertisingConsent(granted)Grant/revoke IDFA/GAID consent
Reflect.setExternalDeviceId(id)Attach a customer-owned device identifier
Reflect.requestIosTracking()Request iOS ATT permission (returns status)
Reflect.getInstallUuid()Get persistent install UUID
Reflect.getAttribution()Get cached attribution data
Reflect.getAttributionWithTimeout(ms)Force a fresh attribution check, resolving early or after the timeout
Reflect.onAttribution(listener)Subscribe to attribution changes (returns unsubscribe fn)
Reflect.updateConversionValue(...)Update SKAN CV (iOS only)
Reflect.getInitialDeepLink()Get the deep link that opened the app
Reflect.getLastDeepLink()The last deep link handled (cold/warm/deferred)
Reflect.onDeepLink(listener)Subscribe to deep link events (returns unsubscribe fn)
Reflect.resolveDeepLink(url)Unshorten/resolve a branded tracking URL via the server
Reflect.handleDeepLink(url)Feed the SDK a link the app captured itself
Reflect.setPushToken(token)Sticky push token stamped on every event
Reflect.setIntegrityToken(token)Supply a Play Integrity / App Attest token (anti-fraud)
Reflect.setAudience(...tags)Tag install for audience segmentation
Reflect.deleteUserData()GDPR — delete all user data
Reflect.setEnabled(enabled)Enable/disable at runtime
Reflect.isEnabled()Whether measurement is currently enabled
Reflect.setOfflineMode(offline)Pause/resume sending (keeps tracking + queuing on-device)
Reflect.flush()Force-flush buffered events

Event tracking

// Custom event
Reflect.trackEvent('level_complete', { level: 5, score: 12340 });

// Revenue
Reflect.trackRevenue({
  amount: 4.99,
  currency: 'USD',
  productId: 'gems_500',
  transactionId: 'txn_abc123',
});

// Attribute installs/revenue to an email (pass it RAW — the server hashes it;
// only sent while consent is not denied).
Reflect.setEmail('[email protected]');
Reflect.clearEmail();   // on logout

The SDK sends the event property bag on the wire as properties; the server maps it to its canonical props field, so props.email reaches attribution.

Deep linking

import { useEffect } from 'react';
import { Reflect } from '@reflect-sdk/react-native';

function App() {
  useEffect(() => {
    // Cold launch deep link (incl. server-resolved deferred links)
    Reflect.getInitialDeepLink().then(data => {
      if (data) navigate(data.path);
    });

    // Warm deep links
    const unsub = Reflect.onDeepLink(data => {
      navigate(data.path);
    });

    return unsub;
  }, []);
}

Android captures warm (onNewIntent) and cold-launch links automatically. On iOS, forward the URL callbacks from your AppDelegate into the module (ReflectModule.stashLaunchURL: / handleURL:) — see the package README for the exact hooks.

SKAN (iOS)

const result = await Reflect.updateConversionValue(42, 'high', false);
if (!result.success) console.warn('SKAN error:', result.error);

Standard events

Pre-built helpers with typed parameters:

import { signUpWith, levelCompleted, addedToCart, adShown } from '@reflect-sdk/react-native';

signUpWith('google');
levelCompleted(5, 12340);
addedToCart('gems_500', 4.99, 'USD');
adShown('admob', 'interstitial', 0.02, 'USD');

Global properties & audience

Reflect.setGlobalProperty('ab_group', 'variant_b');
Reflect.setAudience('whale', 'early_adopter');

Purchase & subscription

Reflect.trackPurchase({
  productId: 'gems_500',
  price: 4.99,
  currency: 'USD',
  receiptData: '<base64>',
});

Reflect.trackSubscription({
  productId: 'pro_monthly',
  price: 9.99,
  currency: 'USD',
  isTrial: true,
});

// Verify a receipt server-side without tracking (returns a typed result)
const result = await Reflect.verifyPurchase({
  productId: 'gems_500',
  transactionId: 'txn_abc123',
  receiptData: '<base64>',
});

Privacy (GDPR)

const deleted = await Reflect.deleteUserData();
// Clears local state + sends server deletion request
v2.0.0 — shared native core, signed ingest
Running on the shared ReflectCore, the SDK now HMAC-signs ingest, and gains server-side receipt verification (verifyPurchase), mediated ad revenue (trackAdRevenue), partner parameters & sharing controls, ATT (requestIosTracking), attestation tokens (setIntegrityToken), link resolution (resolveDeepLink/handleDeepLink), and offline-mode / enable toggles — on top of the existing v1 track, consent, deep-link, and SKAN API.