Rheo documentation
Developer Guide

Bare React Native SDK

Install and integrate @getrheo/react-native-bare — RheoProvider, Flow, native video/review adapters, and full API reference.

Package

@getrheo/react-native-bare — bare React Native entry point. Re-exports @getrheo/react-native-core and registers bare adapters:

CapabilityAdapter
Video layersreact-native-video
In-app review buttonsreact-native-in-app-review

Do not install @getrheo/react-native-expo alongside this package.

The public JavaScript API is identical to the Expo flavor — only native adapters and peer dependencies differ. Shared runtime concepts: SDK overview.

Runnable reference: getrheo/rheo-example-bare (public). Full-stack local API testing uses the private Rheo monorepo example via pnpm dev:local:app:react-native.

Install

pnpm add @getrheo/react-native-bare \
  react react-native \
  react-native-permissions react-native-gesture-handler react-native-reanimated \
  react-native-linear-gradient react-native-svg lottie-react-native \
  react-native-vector-icons @react-native-async-storage/async-storage \
  react-native-safe-area-context react-native-in-app-review react-native-video

@react-native-community/slider and @react-native-community/datetimepicker ship as direct dependencies of core.

Integrations (not SDK peers): react-native-appsflyer, react-native-purchases, react-native-purchases-ui, @superwall/react-native-superwall — install only when used.

Native setup

iOS

cd ios && pod install
  1. Permissions — for each permissionKey your flows request, add entries via react-native-permissions setup_permissions in Podfile and matching Info.plist usage strings (NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSCalendarsFullAccessUsageDescription, etc.).
  2. Videoreact-native-video follows its upstream linking guide (autolinking on RN 0.60+).
  3. Fonts — link custom branding fonts or load at runtime before text renders.

Android

  1. Add AndroidManifest.xml permissions for each capability (CAMERA, RECORD_AUDIO, READ_MEDIA_IMAGES, POST_NOTIFICATIONS on API 33+, etc.).
  2. Rebuild after changing permissions.

Root layout

import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { RheoProvider } from '@getrheo/react-native-bare';

const App = () => (
  <SafeAreaProvider>
    <GestureHandlerRootView style={{ flex: 1 }}>
      <RheoProvider config={rheoConfig}>
        <Navigation />
      </RheoProvider>
    </GestureHandlerRootView>
  </SafeAreaProvider>
);

react-native-gesture-handler must be imported at the app entry (see upstream docs) when using navigators.

OS permissions

Same built-in keys as Expo — notifications, camera, microphone, photo_library, contacts, calendar. The SDK calls react-native-permissions internally; there is no host permission callback.

Configure native projects per the react-native-permissions checklist. Missing setup → outcome denied.

Branding fonts

import { buildBrandingFontLoadMap } from '@getrheo/react-native-bare';

const fontMap = buildBrandingFontLoadMap(branding);
// Load with react-native-asset linking or a runtime loader before Flow mounts

Step-by-step integration

1. Credentials

Copy publishable key from App settings → SDK credentials and channel public id from Channels. See SDK environment.

2. RheoConfig

import type { RheoConfig } from '@getrheo/react-native-bare';

const rheoConfig: RheoConfig = {
  publishableKey: 'ob_pk_test_xxxxxxxx',
  apiBaseUrl: __DEV__ ? 'http://10.0.2.2:4000' : undefined, // Android emulator → host
  userId: persistedUserId, // load from AsyncStorage — do not omit on RN
  sessionId: `sess_${Date.now()}`,
  appVersion: DeviceInfo.getVersion(),
  locale: 'en',
};

Full field reference: Expo SDK — RheoConfig (same type).

3. RheoProvider

import { RheoProvider } from '@getrheo/react-native-bare';

<RheoProvider config={rheoConfig} prefetch={['ch_test_onboarding']}>
  <RootNavigator />
</RheoProvider>

Optional logLevel ("silent" | "warn" | "debug", default silent) controls SDK console diagnostics. See Diagnostics and logging.

4. <Flow />

import { Flow } from '@getrheo/react-native-bare';
import type { FlowTerminalSnapshot } from '@getrheo/react-native-bare';

const PaywallGate = () => (
  <Flow
    channelId="ch_live_paywall_01"
    theme="light"
    onFlowCompleted={(payload: FlowTerminalSnapshot) => {
      navigation.replace('Home');
      analytics.track('onboarding_complete', payload.correlation);
    }}
    fallback={<StaticPaywall />}
  />
);

5. Custom UI with useFlow

Same API as Expo — import from @getrheo/react-native-bare:

import {
  useFlow,
  LayerRenderer,
  ScreenChrome,
} from '@getrheo/react-native-bare';

See Expo SDK — managed vs custom for the full useFlow / LayerRenderer pattern.

Identity

import { useRheoCustomUserId } from '@getrheo/react-native-bare';

const { setCustomUserId } = useRheoCustomUserId();
// After your auth session resolves:
setCustomUserId(backendUser.id);

Persist userId yourself (AsyncStorage) so experiment bucketing stays stable across launches.

Manifest prefetch

Identical to Expo — import from @getrheo/react-native-bare:

import { prefetch, prefetchAll, useRheoPrefetch } from '@getrheo/react-native-bare';

<RheoProvider config={config} prefetch="all" />

// Imperative:
void prefetch('ch_test_…');

In-app review

Requires react-native-in-app-review (listed in install command). Buttons with action.kind: "request_app_review" call the native review API with the same ~1.5s iOS delay behavior as Expo.

Video layers

video layers use react-native-video. Ensure the native module is linked and test on device — simulators may not reproduce all playback edge cases.

Events, terminal payloads, auth, paywalls

Export reference

Same surface as @getrheo/react-native-expo — import from @getrheo/react-native-bare:

CategoryExports
ProviderRheoProvider, useRheo, useRheoCustomUserId, useEventQueue
Flow UIFlow, useFlow, LayerRenderer, ScreenChrome, DefaultResolveError
Prefetchprefetch, prefetchAll, useRheoPrefetch
AuthOAuthLoginProvider, EmailPasswordAuthProvider, useOAuthLogin, useEmailPasswordAuth
IntegrationspresentRevenueCatPaywall, normalizeRcPaywallResult, presentSuperwallPaywall, normalizeSuperwallResult, externalSurfaces / ExternalSurfaceHostProps, attribution helpers
TypesRheoConfig, FlowTerminalSnapshot, UseFlowResult, FlowProps, manifest types
ErrorsRheoChannelRequiredError, RheoChannelNotFoundError, RheoChannelArchivedError
CacheclearManifestResolveCache, listManifestResolveCacheEntries, manifestResolveCacheKey

HTTP API

EndpointPurpose
POST /v1/sdk/resolveChannel manifest + assignment
POST /v1/sdk/resolve-allBatch prefetch
POST /v1/sdk/eventsAnalytics batch

Headers: Authorization: Bearer <publishableKey>, X-Rheo-Channel: <channelId> (resolve and per-channel event batches).

Expo vs bare — when to pick bare

Choose bare when…Choose Expo when…
You own ios/ and android/ nativelyYou use Expo Router / dev client
You already depend on react-native-videoYou prefer expo-video + config plugins
You cannot use Expo prebuildYou want npx expo install peer alignment