Skip to main content
Configure FlowPilot once, as early as possible at app launch, before you present any placement. You pass a FlowPilotConfiguration object to FlowPilot.configure(...). After that, you reach the SDK through the same FlowPilot singleton you imported.
Before you startYou need:

Configure at launch

Call FlowPilot.configure(...) with at least an apiKey and an appId. Do it at module load or in your root component, before any flow is presented.
import { FlowPilot } from '@flowpilotjs/react-native-sdk';

FlowPilot.configure({
  apiKey: 'fp_live_xxxxxxxxxxxxxxxx',
  appId: 'your-app-id',
  environment: 'production',
  context: {
    'user.id': 'user_123',
    'user.is_premium': false,
  },
});
FlowPilot.configure(...) validates the configuration synchronously and throws if the API key does not start with fp_, or if appId is empty. Wrap it in a try/catch if you build the key from a value that might be missing.
Configuration throws on an invalid API key, it does not silently no-op. This differs from the iOS SDK (which leaves FlowPilot.shared nil). If configure throws and you swallow it, every later presentPlacement throws SDK_NOT_INITIALIZED instead.

Where the credentials come from

  • apiKey is an SDK API key for your app. Create one in the dashboard (it is shown only once). It is not your dashboard login. See API keys.
  • appId is the App ID of the app that owns your placements. See Workspaces and apps.
Do not hardcode a live API key in source you commit. Inject it from an environment variable (for example through app.config.js / expo-constants) or your build’s secrets, not a checked-in string.

Configuration options

FlowPilotConfiguration has two required fields; the rest are optional with sensible defaults.
apiKey
string
required
Your workspace SDK API key. Must start with fp_. From API keys.
appId
string
required
The App ID that owns your placements. From Workspaces and apps.
environment
'development' | 'staging' | 'production' | { baseUrl: string }
default:"'production'"
Which FlowPilot backend to talk to, and the default cache freshness. Pass a named environment or a custom { baseUrl } for a self-hosted or test backend. The named environments also set the default cache TTL: development is 0 (no caching by default), staging is 60 seconds, production is 300 seconds. See Caching.
context
Record<string, unknown>
default:"undefined"
Initial SDK context for variable resolution and audience targeting, as a flat key/value map (for example { 'user.id': '123', 'user.is_premium': true }). Keys can use dot notation to match how variables reference them. See Variables and context.
cachingEnabled
boolean
default:"true"
Whether resolved flows are cached (in memory and on disk). Caching makes repeat presents fast and powers offline fallback. Disabling it also disables prefetching. See Caching.
mediaPreloadingEnabled
boolean
default:"true"
Whether images are preloaded in screen order when a session is created, so users do not see loading states while navigating. See Media preloading.
resolveTimeout
number
default:"4"
Hard wall-clock deadline, in seconds, for a live resolve before the fail-safe chain falls back to stale cache, then a bundled default, then an error. Values are floored at 0.5. Hitting the deadline degrades the current caller to a fallback tier but does not cancel the in-flight resolve (it keeps running to warm the cache for the next caller). See Caching.
prefetchOnLaunch
string[]
default:"[]"
Placement keys to warm automatically, once, in the background right after configure(...). Warming never blocks startup: it caches each flow’s JSON and fonts, plus images per prefetchMediaStrategy, so a later present hits the cache. No-op when cachingEnabled is false. Warmed entries only survive their freshness TTL, so this has no visible effect against a 0-TTL backend (development). See Prefetching.
prefetchMediaStrategy
'none' | 'firstScreen' | 'allScreens'
default:"'firstScreen'"
How aggressively launch prefetch warms images: none (JSON + fonts only), firstScreen (also first-screen and persistent-zone images, the default), or allScreens (also every screen’s images). Also bounds the screen window when an explicit prefetch(..., { warmMedia: true }) call opts into media warming. See Prefetching.
bundledFlows
Record<string, object | (() => object | null)>
default:"{}"
Build-time offline default flows, keyed by placement key. Unlike iOS (which loads a bundle resource by name), React Native has no such lookup: pass the flow JSON directly, typically require('./flows/onboarding.json') (Metro inlines it as an object), an already-parsed object, or a lazy loader thunk. See Offline and bundled flows.
bundledFlowAssets
Record<string, BundledFlowAssets>
default:"{}"
Offline image, icon, and font assets for bundled flows, keyed by the same placement key as bundledFlows, so a bundled default renders with no network at all. Usually produced by the flowpilot-export CLI. See Offline and bundled flows.
logLevel
'none' | 'error' | 'warn' | 'info' | 'debug' | 'verbose'
default:"'info'"
How much the SDK logs to the console. Raise to debug or verbose to see resolves, the delivery source, and validation failures.
The three named environments (development, staging, production) currently resolve to the same API host (https://api.getflowpilot.io/api); they differ mainly in their default cache TTL. Use a custom { baseUrl } to point at a different host.
TODO: confirm the per-environment base URLs against flowpilot-EXPO-SDK/src/core/Configuration.ts (BASE_URLS) once distinct staging/production hosts are wired up.

Example

A complete launch configuration with context for targeting, a bundled offline default, and launch prefetch:
import { FlowPilot } from '@flowpilotjs/react-native-sdk';

FlowPilot.configure({
  apiKey: process.env.EXPO_PUBLIC_FLOWPILOT_API_KEY ?? '',
  appId: 'app_ios_main',
  environment: 'production',
  context: {
    'user.id': 'user_123',
    'user.is_premium': false,
    'user.plan': 'free',
  },
  resolveTimeout: 4,
  bundledFlows: {
    onboarding: require('./flows/onboarding.json'),
  },
  prefetchOnLaunch: ['onboarding'], // warm onboarding in the background
  prefetchMediaStrategy: 'firstScreen',
  logLevel: 'info',
});

Updating context after login

The Expo SDK reads context at configure time and when each session is created. There is no public updateContext method on FlowPilot in this build (unlike the iOS SDK). To change the identity or attributes after login, call configure again with the new context, before you present the next flow.
// After the user signs in:
FlowPilot.configure({
  apiKey: process.env.EXPO_PUBLIC_FLOWPILOT_API_KEY ?? '',
  appId: 'app_ios_main',
  context: {
    'user.id': 'user_456',
    'user.is_premium': true,
    'user.plan': 'pro',
  },
});
TODO: if a public FlowPilot.updateContext(...) (or per-present context option) is added, document it here and stop recommending re-configure. Verify against flowpilot-EXPO-SDK/src/FlowPilot.ts.

Common mistakes

  • Swallowing the throw. configure throws on a bad API key or empty App ID. Do not wrap it in an empty catch, or you will see SDK_NOT_INITIALIZED later with no clue why.
  • Presenting before configuring. A present or resolve before configure(...) throws SDK_NOT_INITIALIZED. Configure once at startup, before any flow.
  • Hardcoding the API key in committed source. Inject it from an environment variable or secrets file.
  • App ID from the wrong app. The appId must own the placement you present, or the resolve returns no flow.
  • Expecting updateContext. It does not exist in this build. Re-configure to change context.

Troubleshooting

  • Invalid API key. Must start with "fp_". thrown from configure. The apiKey is wrong or unset. Copy it again from Settings -> API Keys in the dashboard.
  • App ID is required. thrown from configure. appId is empty. Pass the App ID that owns your placements.
  • Every present throws SDK_NOT_INITIALIZED. configure never ran (or threw and was swallowed). Move it to app startup and let any thrown error surface during development.
  • A resolve returns no flow. Usually the wrong appId, the wrong environment for the key, or a placement with no published flow. Walk the quickstart checklist.