Quickstart by stack
React Native Quickstart
Install the React Native SDK, wrap your app in FlagsProvider, and read flags with useFlag, useVariant, and FlagGate.
Prerequisites
- React Native 0.72 or newer, or an Expo app. React 18.2 or newer (React 19 works too).
- A mobile key (prefixed mob_) or a client key (prefixed cli_) from your environment. Server keys (srv_) are rejected, because anything bundled in an app can be extracted.
- A flag key you can test in a non-production environment.
npm install @zenmanage/react-native @zenmanage/sdk react react-native
For rules that survive an app restart, add the AsyncStorage package too. It is optional, but recommended. Without it, the SDK keeps rules in memory only.
npm install @react-native-async-storage/async-storage
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { FlagsProvider, useFlag } from '@zenmanage/react-native';
const styles = StyleSheet.create({
wrapper: { padding: 24 },
});
function CheckoutLabel() {
const { value: enabled, isLoading } = useFlag('new-checkout', false);
if (isLoading) {
return <Text>Loading flags...</Text>;
}
return <Text>{enabled ? 'Checkout (New)' : 'Checkout'}</Text>;
}
export function App() {
return (
<FlagsProvider environmentToken="mob_your_mobile_key_here">
<View style={styles.wrapper}>
<CheckoutLabel />
</View>
</FlagsProvider>
);
}
Safe defaults, explicit loading
Every hook takes a default and returns it until the flag resolves, and again if evaluation fails. isLoading and error are explicit, so you decide what the screen shows in each state. The type of the default decides how the flag is read: boolean, string, number, or JSON.
Built on the core SDK
The package wraps @zenmanage/sdk, so caching, context handling, and defaults behave the same way they do in the JavaScript quickstart. Pass your own client to the provider if you already have one.
import { Context } from '@zenmanage/sdk';
import { useIdentify } from '@zenmanage/react-native';
export function useAccountTargeting() {
const { identify, clearIdentity } = useIdentify();
return {
// Refreshes the rules for this user by default.
onSignIn: (userId: string) => identify(Context.single('user', userId)),
// Drops the user context and refreshes again.
onSignOut: () => clearIdentity(),
};
}
Call identify at login and clearIdentity at logout. Use a stable identifier, such as your user ID, so a percentage rollout keeps the same users in the same bucket across launches.
import { useVariant } from '@zenmanage/react-native';
function CheckoutScreen() {
const { variant } = useVariant('checkout-flow', 'control');
if (variant === 'one-page') {
return <OnePageCheckout />;
}
return <MultiPageCheckout />;
}
import { FlagGate } from '@zenmanage/react-native';
<FlagGate
flagKey="beta-chat"
loadingFallback={<Spinner />}
disabledFallback={<LegacyChat />}
>
<BetaChat />
</FlagGate>
Background and foreground refreshes never show loadingFallback. A gated screen stays mounted while rules re-fetch, and its value updates once the new rules land.
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AsyncStorageCache, FlagsProvider } from '@zenmanage/react-native';
const cache = new AsyncStorageCache({
storage: AsyncStorage,
keyPrefix: 'zenmanage',
});
export function App() {
return (
<FlagsProvider environmentToken="mob_your_mobile_key_here" cache={cache} cacheTtl={3600}>
<Root />
</FlagsProvider>
);
}
Refresh with the app lifecycle
The provider refreshes rules when the app returns to the foreground, at most once per minForegroundRefreshIntervalMs (30 seconds by default). Set backgroundRefreshIntervalMs if you also want periodic refreshes while the app is open.
Mobile or client keys only
Use a mob_ or cli_ key in the app. Keys in an app bundle are readable by anyone with the binary, so keep srv_ keys on your backend.
Next step
Take the next integration step in your own stack.
Start with the quickstart that matches your runtime, then return to the reference pages when you need exact request and payload details.
Language and framework names and logos shown above are trademarks or registered trademarks of their respective owners. Their use here is for identification purposes only and does not imply endorsement of, or affiliation with, Zenmanage.