React Native SDK
The Unleash React Native SDK lets you evaluate feature flags in your React Native and Expo applications. It wraps the React SDK and handles two React Native-specific requirements automatically: persistent storage using AsyncStorage instead of localStorage, and a polyfill for crypto.getRandomValues.
You can use this SDK with Unleash Enterprise or Unleash Open Source.
Requirements
- React Native 0.81 or later (or equivalent Expo SDK version)
- React 18 or later
Installation
Install the SDK and its required peer dependency, unleash-proxy-client.
npm
yarn
Expo
Configuration
The following options are available when initializing the SDK. Pass them as the config prop on FlagProvider.
The /api/frontend endpoint of your Unleash instance (https://<your-unleash-instance>/api/frontend) or Unleash Edge instance (https://<your-edge-instance>/api/frontend).
A frontend token from your Unleash instance.
The name of your application. Used in metrics, included in the Unleash context, and used as the prefix for local cache keys.
How often (in seconds) the SDK polls for updated flag configuration. Set to 0 to disable polling after the initial fetch.
If true, the SDK does not poll for updates after the initial fetch.
How often (in seconds) the SDK sends usage metrics to Unleash.
If true, the SDK does not send usage metrics.
The storage backend for cached flag configuration. Defaults to AsyncStorageProvider, which uses @react-native-async-storage/async-storage. You can provide a custom implementation that satisfies the IStorageProvider interface.
The initial Unleash context. The SDK automatically sets appName, environment, and a persistent sessionId on the context, so gradual rollouts and session-based targeting work without additional configuration.
Initial flag configuration to use before the SDK connects to Unleash. See bootstrap flag data.
If true, bootstrap data overrides any cached flag configuration. If false, bootstrap data is only used when the cache is empty.
The header name used to send the clientKey to Unleash.
Additional HTTP headers to include in all requests to Unleash.
If true, the SDK emits impression events for all isEnabled and getVariant calls, including flags that are disabled or non-existent.
Initialization
Wrap your application in FlagProvider in your entry point file. All components inside the provider can access feature flags through hooks.
Connection options
Frontend SDKs communicate with Unleash or Unleash Edge through the Frontend API and require a frontend token. Unlike backend SDKs, frontend SDKs do not perform the flag evaluation locally. Instead, they fetch all enabled feature flags for a given Unleash context. The flag evaluation happens either in Unleash Edge, or in the Unleash server, when using the Frontend API directly.
Set url to the /api/frontend endpoint of either your Unleash instance (https://<your-unleash-instance>/api/frontend) or your Edge instance (https://<your-edge-instance>/api/frontend). The URL pattern is the same in both cases. Use Unleash Edge when you need lower latency or higher availability.
Set clientKey to a frontend token. See API tokens for how to generate one.
Check if the SDK is ready
The SDK returns default values (false for useFlag, { name: "disabled", enabled: false } for useVariant) until it loads flag data from one of these sources, checked in this order:
- Bootstrap data: if provided and
bootstrapOverrideistrue(or the cache is empty), the SDK uses bootstrap values immediately andreadyfires before the first network request. - Cached data: on subsequent launches, the SDK loads previously cached flag data from
AsyncStorage. Flags are available, butreadydoes not fire until the SDK also completes a network request. - Network fetch: the SDK fetches flag configuration from Unleash. The
readyevent fires on the first successful response (if it has not already fired from bootstrap).
Use the useFlagsStatus hook to check whether the SDK has completed its first network fetch:
Because flagsReady requires a successful network request, there is a brief loading state on every app launch when you gate rendering on flagsReady, even if cached data exists from a previous session.
If you need instant startup without a loading state, use bootstrapping to provide initial flag values. The SDK uses bootstrap data immediately and fetches the latest flag data from Unleash in the background.
Defer client start
By default, FlagProvider starts polling immediately when the component mounts. To defer this, pass a pre-created client with startClient set to false and call start() when you are ready:
This pattern is also useful when you need to attach event listeners before the SDK starts.
Check flags
Check if a flag is enabled
Use the useFlag hook to check whether a feature flag is enabled:
If the SDK has not yet loaded flag configuration, useFlag returns false. The component re-renders automatically when the SDK receives flag data.
Check a flag’s variant
Use the useVariant hook to get the variant assigned to a feature flag:
If the flag is disabled or has no variants, useVariant returns { name: "disabled", enabled: false }.
Unleash context
The Unleash context determines how flags are evaluated for a given user or session. You can set context fields at initialization and update them at runtime.
Set context at initialization
Pass the context as part of the config object:
Update context at runtime
Use the useUnleashContext hook to update the context after initialization, for example when a user logs in:
updateContext triggers a new flag evaluation request with the updated context. To wait for the updated flags before taking action:
Bootstrap flag data
Bootstrapping lets you provide initial flag values that the SDK uses immediately, before it connects to Unleash. This is useful for guaranteeing a specific flag state at app startup or providing fallback values for offline scenarios.
When bootstrapOverride is true, bootstrap data replaces any flag configuration already cached in AsyncStorage. When bootstrapOverride is false, bootstrap data is only used when the cache is empty.
Local caching and offline behavior
The SDK caches data in AsyncStorage under two keys, both prefixed with the appName from your config:
{appName}:repo: the flag data returned by Unleash.{appName}:sessionId: a persistent session identifier used for [gradual rollouts](/concepts/activation-strategies#gradual-rollout, constraints, and stickiness.
On each app launch, the SDK reads both values from AsyncStorage before making a network request. The session ID is generated once and persists across app restarts, which keeps flag evaluation consistent across sessions.
The flag data cache is updated after every successful network fetch.
What happens when Unleash is unreachable
If the SDK cannot connect to Unleash on startup and no bootstrapped values are configured, useFlag returns false for all flags and useVariant returns { name: "disabled", enabled: false }. The SDK does not have explicit retry logic. It continues to poll on the regular refreshInterval and returns to a healthy state on the next successful response.
If bootstrapped values are configured, the SDK uses those values until it can reach Unleash.
App lifecycle
The SDK does not automatically detect app lifecycle changes. When the app is backgrounded, JavaScript timers pause. When the app returns to the foreground, any overdue poll fires, but the timing is not guaranteed.
To fetch fresh flags every time the app comes to the foreground, use AppState from React Native:
Render <AppStateRefresh /> inside FlagProvider alongside your app’s root component.
Events
Use the useUnleashClient hook to access the underlying client and attach event listeners:
If you need to capture events that fire during initialization (such as initialized or ready), use the deferred client start pattern to attach listeners before the client starts.
Unit testing
To test components that use feature flags, wrap them in a FlagProvider with bootstrapped values. This avoids network requests during tests and gives you full control over flag state.
Set disableRefresh and disableMetrics to true in tests to prevent the SDK from making network requests. Use startClient={false} to prevent polling.
Alternatively, you can mock the hooks directly in your test framework:
Troubleshooting
The SDK is not connecting to Unleash
If the SDK does not load flags on startup:
- Verify that
urlpoints to the/api/frontendendpoint of your Unleash instance (https://<your-unleash-instance>/api/frontend) or Edge instance (https://<your-edge-instance>/api/frontend). The URL must include the full path. - Verify that
clientKeyis a valid frontend token. A 401 response means the token is invalid or does not have access to the requested environment. - Check that your device or simulator has network access to your Unleash instance.
Use useFlagsStatus to surface connection errors:
Flags always return false or the disabled variant
If useFlag always returns false or useVariant always returns { name: "disabled", enabled: false }:
- Confirm that
flagsReadyistrue. Until the SDK loads flag data from bootstrap, cached storage, or a network fetch, all hooks return default values. - Confirm that the flag is enabled in the correct Unleash environment and that your frontend token has access to that environment and project.
- Check the Unleash context. If your flag uses a gradual rollout or user-based targeting, the
userIdorsessionIdmust match the targeting rules configured in Unleash. If your flag uses custom stickiness, you must set that value in the context, otherwise the flag evaluates tofalse. Use Playground for testing different context values.
Loading state on every app launch
flagsReady requires a successful network fetch before it becomes true, even when cached data exists from a previous session. If you gate rendering on flagsReady, there is a brief loading state on every launch.
To eliminate the loading state, use bootstrapping to provide initial flag values. The SDK uses bootstrap data immediately and fetches the latest flag data from Unleash in the background.