Installation
npm install @omniretail/omniflags-react-native @react-native-async-storage/async-storage
Follow the AsyncStorage native setup to link the native module.
Peer dependencies: React Native 0.68+, @react-native-async-storage/async-storage 1.0+
Setup
import { OmniFlagsProvider } from '@omniretail/omniflags-react-native';
export default function App() {
return (
<OmniFlagsProvider sdkKey="pk_live_...">
<RootNavigator />
</OmniFlagsProvider>
);
}
Flags are available immediately on launch from the local cache, with a background refresh running in parallel. This applies on subsequent launches even when the device is offline.
First launch
No cache exists on a fresh install, so flags start loading. Gate on isLoading from useFlagStatus if your app needs flags before it can render:
import { useFlagStatus } from '@omniretail/omniflags-react-native';
function AppShell() {
const { isLoading } = useFlagStatus();
if (isLoading) return <SplashScreen />;
return <RootNavigator />;
}
After the first snapshot is cached this won’t trigger again, even offline.
Hooks
Same hooks as the React SDK, imported from @omniretail/omniflags-react-native.
useFlag
Boolean flag evaluation. Re-renders only when this flag’s value changes.
import { useFlag } from '@omniretail/omniflags-react-native';
function CheckoutScreen({ customerId }: { customerId: string }) {
const chargeDeliveryFee = useFlag('checkout.charge-delivery-fee', { customerId });
return (
<View>
<Text>{chargeDeliveryFee ? 'Delivery fee applies' : 'Free delivery'}</Text>
</View>
);
}
| Parameter | Type | Default | Description |
|---|
flagKey | string | required | {projectKey}.{flagKey} |
context | EvaluationContext | {} | Targeting attributes |
defaultValue | boolean | false | Fallback when flag is missing, wrong type, or client not ready |
useFlagValue
Returns the typed value of any flag — string, number, or object.
import { useFlagValue } from '@omniretail/omniflags-react-native';
function PromoBanner({ customerId }: { customerId: string }) {
const colour = useFlagValue('product-listing.promo-banner-colour', 'blue', { customerId });
return (
<View style={{ backgroundColor: colour }}>
<Text>Limited time offer</Text>
</View>
);
}
const config = useFlagValue<CheckoutConfig>('checkout.config', defaultConfig, { customerId });
| Parameter | Type | Required | Description |
|---|
flagKey | string | yes | {projectKey}.{flagKey} |
defaultValue | T | yes | Fallback value |
context | EvaluationContext | no | Targeting attributes |
useFlagVariant
Returns the full EvaluationResult — variant key, reason, and rule ID.
import { useFlagVariant } from '@omniretail/omniflags-react-native';
function BannerWithAnalytics({ customerId }: { customerId: string }) {
const result = useFlagVariant('product-listing.promo-banner-colour', { customerId });
useEffect(() => {
analytics.track('flag_evaluated', {
flag: 'product-listing.promo-banner-colour',
variant: result.variant,
reason: result.reason,
});
}, [result.variant]);
return <Banner colour={result.value as string} />;
}
| Field | Type | Description |
|---|
value | unknown | Resolved flag value |
variant | string | null | Matched variant key |
reason | EvaluationReason | See reason codes |
ruleId | string | null | Matched rule ID, if any |
errorCode | ErrorCode | null | Set when reason is ERROR |
useFlagStatus
Current state of the flag client.
import { useFlagStatus } from '@omniretail/omniflags-react-native';
function DebugOverlay() {
const { isLoading, isFetching, origin, error } = useFlagStatus();
return (
<Text style={styles.debug}>
Flags: {isLoading ? 'loading' : origin} {isFetching ? '(refreshing)' : ''}
</Text>
);
}
| Field | Type | Description |
|---|
isLoading | boolean | true until the first snapshot loads (cache or network) |
isFetching | boolean | true while a network request is in flight |
origin | 'NONE' | 'CACHE' | 'SERVER' | Source of the active snapshot |
error | Error | null | Last fetch error |
useSetFlagContext
Sets a global evaluation context for the whole provider tree. Individual hook calls that pass their own context will be merged with it — per-call attributes win on conflict.
import { useSetFlagContext } from '@omniretail/omniflags-react-native';
function AuthenticatedNavigator({ user }: { user: CurrentUser }) {
useSetFlagContext({
customerId: user.id,
country: user.country,
platform: Platform.OS,
});
return <RootNavigator />;
}
Clears on unmount.
| Parameter | Type | Description |
|---|
context | EvaluationContext | undefined | Pass undefined to clear explicitly. |
Evaluation context
Attributes used to match targeting rules and assign rollout buckets. Pass per-hook or once globally via useSetFlagContext.
useFlag('checkout.charge-delivery-fee', {
customerId: '4821',
country: 'Nigeria',
city: 'Lagos',
platform: 'android',
appVersion: '4.1.0',
});
| Attribute | Type | Notes |
|---|
customerId | string | number | Primary bucketing key |
agentId | string | number | Used when customerId is absent |
businessId | string | number | |
businessBranchId | string | number | |
country | string | e.g. "Nigeria", "Ghana" |
city | string | |
platform | string | web, ios, android |
appVersion | string | Semver string |
Any extra key-value pairs are forwarded to targeting rules as custom attributes.
Rollout and traffic splits require a bucketing key (customerId, agentId, etc.). Without one the SDK returns the flag’s default value with MISSING_TARGETING_KEY.
Offline support
The last successful snapshot is persisted locally and loaded on the next launch before any network activity.
origin is 'CACHE' while a background fetch is pending, 'SERVER' once it completes.
- On fetch failure
origin stays 'CACHE' and flags keep serving from the cached snapshot.
Foreground refresh
A snapshot refresh is triggered automatically when the app returns to the foreground. Flag changes made in the dashboard reach active users without requiring an app restart.