Expo SDK

@onramp-sdk/react-native works with both the Expo managed and bare workflows. This page covers the Expo-specific setup steps.

The React Native + Expo example app shows the full flow, including milestone and navigation tracking.


Installation

bash
npx expo install @onramp-sdk/react-native @react-native-async-storage/async-storage

Using npx expo install (rather than npm install) ensures the correct compatible version of async-storage is selected for your Expo SDK version.


Managed workflow

No additional configuration is needed. The SDK uses only JavaScript and the standard Expo-compatible async-storage package.

Call OnRamp.init() once at app start - before any OnRamp.step() calls:

tsx
import { useEffect } from 'react'
import { OnRamp } from '@onramp-sdk/react-native'

export default function App() {
  useEffect(() => {
    OnRamp.init({ apiKey: 'onr_xxxxxxxxxxxx', appVersion: '1.0.0' })
  }, [])

  return <YourApp />
}

Bare workflow

Follow the same setup as React Native. After adding the SDK, run:

bash
npx pod-install

Expo Router

If you are using Expo Router, initialize OnRamp in your root layout and call OnRamp.step() to track milestones:

tsx
// app/_layout.tsx
import { useEffect } from 'react'
import { Stack } from 'expo-router'
import { OnRamp } from '@onramp-sdk/react-native'

export default function RootLayout() {
  useEffect(() => {
    OnRamp.init({ apiKey: 'onr_xxxxxxxxxxxx', appVersion: '1.0.0' })
  }, [])

  return <Stack />
}

To track screen transitions in Expo Router, use the usePathname hook from expo-router and fire OnRamp.step() when the pathname changes:

tsx
// app/_layout.tsx
import { useEffect } from 'react'
import { usePathname, Stack } from 'expo-router'
import { OnRamp } from '@onramp-sdk/react-native'

function RouteTracker() {
  const pathname = usePathname()
  useEffect(() => {
    if (pathname) OnRamp.step(pathname, { _eventType: 'nav_entered', properties: { _nav: true } })
  }, [pathname])
  return null
}

export default function RootLayout() {
  useEffect(() => {
    OnRamp.init({ apiKey: 'onr_xxxxxxxxxxxx', appVersion: '1.0.0' })
  }, [])

  return (
    <>
      <RouteTracker />
      <Stack />
    </>
  )
}

The NavigationTracker component wraps a React Navigation NavigationContainer and won't work with Expo Router (which manages its own navigation). Use the usePathname pattern above instead.


React Navigation (bare / SDK-style)

If you're using React Navigation inside Expo, wrap your NavigationContainer with NavigationTracker:

tsx
import { NavigationContainer } from '@react-navigation/native'
import { NavigationTracker } from '@onramp-sdk/react-native'

<NavigationTracker>
  <NavigationContainer>
    {/* your navigators */}
  </NavigationContainer>
</NavigationTracker>

Attribution

Deep link attribution works out of the box with no extra dependency - the SDK uses React Native's own Linking module (getInitialURL() / addEventListener('url', ...)), which is available in both the Expo managed and bare workflows, including Expo Go. It's off by default - pass captureInstallReferrer: true to OnRamp.init() to turn it on.

Configuring the Universal Link (associatedDomains) or App Link (intentFilters) itself is a separate Expo config step (in app.json/app.config.ts) and is unrelated to the SDK - the SDK only reads the URL once your app is already set up to receive it.

If you already use an MMP (Adjust, AppsFlyer, Branch, etc.), leave captureInstallReferrer at its default false and call OnRamp.setAttribution() from its callback instead - that works regardless of the flag. See the React Native SDK's Attribution section for the full API and the reasoning behind the opt-in default.

Android Play Install Referrer and iOS Apple Search Ads (see the React Native SDK's Attribution section) both require the SDK's native modules, which means an EAS bare-workflow rebuild - they aren't available in Expo Go, which can't load custom native code. If you're on Expo Go or the managed workflow without a dev client, setAttribution() above is the way to bring in that data today if you already have it from your own MMP.


EAS Build

Your app key is safe to bundle - it is not a secret. If you want separate keys per environment, use Expo's app config:

ts
// app.config.ts
export default {
  extra: {
    onrampKey: process.env.ONRAMP_APP_KEY,
  },
}
tsx
import Constants from 'expo-constants'

OnRamp.init({ apiKey: Constants.expoConfig?.extra?.onrampKey ?? '' })

For the full SDK API, see the React Native SDK reference.