Skip to main content
@traffical/react-native is the SDK for iOS and Android apps built with React Native. It handles the constraints mobile imposes — cold starts, offline use, app suspension, device context — and ships with sensible defaults so most apps don’t have to think about them.

Why mobile is different

Mobile has constraints web and backend don’t:
  • Cold start. On first launch there’s no cached bundle and no network response yet. The user sees the app before any experiment can resolve.
  • Offline use. Users open the app on planes and in subways. Resolution must work without connectivity.
  • App store latency. Code changes take days. Parameter changes via Traffical are instant — this is the whole point of having a remote configuration system at all.
  • Background suspension. The app may be paused for hours and resumed. Cached assignments need refreshing.
The React Native SDK defaults to evaluationMode: "server" (each resolution is a network call, with the response cached), backed by AsyncStorage for persistence across launches. You can override with evaluationMode: "bundle" if you’d rather embed the full bundle.

Installation

npm install @traffical/react-native @react-native-async-storage/async-storage
For iOS, run pod install in the ios/ directory after adding @react-native-async-storage/async-storage.

Setup

import { TrafficalRNProvider } from "@traffical/react-native";

function App() {
  return (
    <TrafficalRNProvider config={{
      orgId: "org_acme",
      projectId: "proj_marketplace",
      env: "production",
      apiKey: "traffical_sk_...",
    }}>
      <Navigator />
    </TrafficalRNProvider>
  );
}
Use an SDK key (traffical_sk_..., scopes sdk:read+sdk:write) — browser-safe. The SDK auto-registers the AsyncStorage cache and lifecycle hooks for foreground/background transitions.

Resolving parameters

Same hook as the React SDK:
import { useTraffical } from "@traffical/react-native";

function Onboarding() {
  const { params } = useTraffical({
    defaults: {
      "mobile.onboarding_steps": 3,
      "mobile.onboarding_style": "carousel",
    },
  });

  return (
    <OnboardingCarousel
      steps={params["mobile.onboarding_steps"]}
      style={params["mobile.onboarding_style"]}
    />
  );
}

Cold start strategy

Resolution checks three sources in order:
PrioritySourceWhen availableStaleness
1Cached assignments (AsyncStorage)After first successful resolveRefreshed per session
2localConfig bundle (baked into the app binary)Always (compiled in)As of the last app build
3Caller defaults from getParamsAlwaysHardcoded fallback
First launch, no localConfig: the user sees defaults until the first network call returns. If your first-launch onboarding is a critical experiment, embed a localConfig bundle built during CI:
<TrafficalRNProvider config={{
  orgId: "org_acme",
  projectId: "proj_marketplace",
  env: "production",
  apiKey: "traffical_sk_...",
  localConfig: require("./traffical-bundle.json"),    // generated by CI
}}>
Returning user: the SDK reads cached assignments from AsyncStorage synchronously before the first render. The user immediately sees their previous-session assignment. A background refresh updates for next time. Returning user after long absence (cache expired): falls back to localConfig, then to caller defaults.

Device-info enrichment

The SDK can enrich context with device info — useful for OS-specific experiments and analytics:
import { TrafficalRNProvider, defaultDeviceInfoProvider } from "@traffical/react-native";

<TrafficalRNProvider config={{
  orgId, projectId, env, apiKey,
  deviceInfoProvider: defaultDeviceInfoProvider,
}}>
This adds fields to every resolution:
{
  appVersion: "2.1.0",
  osName: "ios" | "android",
  osVersion: "17.4",
  locale: "en-US",
  screenWidth: 390,
  screenHeight: 844,
  deviceModel: "iPhone 15",
}
These are available for policy conditions — e.g. osName eq "ios" for an iOS-only experiment, or appVersion gte "2.0.0" to scope a feature flag to a minimum version.

Tracking events

import { useTrafficalTrack } from "@traffical/react-native";

function PaywallScreen() {
  const track = useTrafficalTrack();
  return <Button onPress={() => track("paywall_purchase_started")} title="Subscribe" />;
}
Events are batched in memory and flushed on background or app close.

Foreground refresh

When the app returns to the foreground after being suspended, the SDK checks whether the cache is stale and refreshes silently if so. Existing assignments stay stable — the refresh only matters for new parameters or next-session resolutions.

Options

OptionTypeDefaultDescription
orgId, projectId, env, apiKeyrequiredSame as other SDKs
evaluationMode"bundle" | "server""server"Mobile-friendly default
localConfigConfigBundleEmbedded bundle for cold-start
deviceInfoProviderDeviceInfoProviderDevice-context enrichment
storageStorageProviderAsyncStorageCustom persistence

Next steps

Mobile experiment pattern

Onboarding and in-app experiments.

How it works

Evaluation modes and resolution.