React Native SDK

The @flagify/react package works in React Native and Expo with zero additional setup. No separate package, no polyfills — the same SDK you use on the web works on mobile.

Requirements

DependencyMinimum version
React Native0.64+
Expo SDK44+
React18+

Getting started with Expo

1. Create a new project

npx create-expo-app@latest my-app
cd my-app

2. Install the SDK

npx expo install @flagify/react

3. Add the provider

Wrap your app with FlagifyProvider in your root layout. With Expo Router, this is app/_layout.tsx:

import { Stack } from 'expo-router';
import { FlagifyProvider } from '@flagify/react';

export default function RootLayout() {
  return (
    <FlagifyProvider
      projectKey="my-project"
      publicKey="pk_dev_abc123_xxxxxxxx"
      options={{ realtime: true }}
    >
      <Stack />
    </FlagifyProvider>
  );
}

4. Use hooks in any screen

import { View, Text } from 'react-native';
import { useFlag } from '@flagify/react';

export default function HomeScreen() {
  const showNewOnboarding = useFlag('new-onboarding');

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      {showNewOnboarding
        ? <Text>Welcome to the new experience!</Text>
        : <Text>Welcome back!</Text>
      }
    </View>
  );
}

Getting started with bare React Native

npm install @flagify/react

Wrap your root App.tsx with the provider:

import React from 'react';
import { FlagifyProvider } from '@flagify/react';
import { HomeScreen } from './screens/HomeScreen';

export default function App() {
  return (
    <FlagifyProvider
      projectKey="my-project"
      publicKey="pk_dev_abc123_xxxxxxxx"
      options={{ realtime: true }}
    >
      <HomeScreen />
    </FlagifyProvider>
  );
}

Then use hooks in any component, exactly like the Expo example above.

Full example: feature-gated screen

import { View, Text, ActivityIndicator, StyleSheet } from 'react-native';
import { useFlag, useIsReady, useVariant } from '@flagify/react';

export default function ProfileScreen() {
  const isReady = useIsReady();
  const showPremiumBadge = useFlag('premium-badge');
  const layout = useVariant('profile-layout', 'classic');

  if (!isReady) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" />
      </View>
    );
  }

  return (
    <View style={styles.container}>
      {showPremiumBadge && <Text style={styles.badge}>Premium</Text>}
      {layout === 'modern'
        ? <ModernProfile />
        : <ClassicProfile />
      }
    </View>
  );
}

const styles = StyleSheet.create({
  center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  container: { flex: 1, padding: 16 },
  badge: { color: '#0D80F9', fontWeight: 'bold', fontSize: 12 },
});

Real-time updates

SSE streaming works the same way in React Native as it does on the web. The SDK uses fetch streaming internally (not EventSource), which is natively supported in React Native 0.64+.

Set realtime: true on the provider and all hooks will automatically re-render when flags change.

Debug logging

To surface SSE connect/reconnect/sync logs from the underlying @flagify/node client, the SDK reads process.env.FLAGIFY_DEBUG === "1" at module load. Off by default — production bundles stay quiet.

React Native and Expo do not inline arbitrary process.env.* into the JS bundle out of the box: Expo only inlines vars prefixed with EXPO_PUBLIC_, and bare RN inlines nothing without a Babel plugin. The SDK does not look for prefixed copies, and localStorage does not exist on RN, so the activation paths are:

Option A — Babel plugin (works on Expo and bare RN). Install babel-plugin-transform-inline-environment-variables and add it to babel.config.js:

module.exports = {
  plugins: [['transform-inline-environment-variables', { include: ['FLAGIFY_DEBUG'] }]],
};

Then start with the var set:

FLAGIFY_DEBUG=1 npx expo start --clear

Option B — bridge it manually. Set EXPO_PUBLIC_FLAGIFY_DEBUG=1 in your .env (Expo will inline it), and bridge to the SDK’s expected name in App.tsx / _layout.tsx before mounting <FlagifyProvider>:

if (process.env.EXPO_PUBLIC_FLAGIFY_DEBUG === '1') {
  (process.env as Record<string, string>).FLAGIFY_DEBUG = '1';
}

The flag is read once at module load — reload the app after toggling.

Errors that indicate non-recoverable problems (auth failures, failed evaluation after sync, SSE parse errors) always log regardless.

Hooks reference

All hooks from @flagify/react work identically in React Native:

HookReturnsDescription
useFlag(key)booleanEvaluate a boolean flag
useVariant(key, fallback)stringGet the winning variant
useFlagValue<T>(key, fallback)TGet a typed flag value
useIsReady()booleanCheck if initial sync is complete
useFlagifyClient()FlagifyAccess the underlying client

For detailed API documentation, see the React SDK reference.