Skip to content

npx expo install @rabolic/react-native

Analytics for your React Native app, on iOS and Android.

One package with no native code of its own, so it works in Expo as it is. Hand it your navigation ref and every screen is tracked; launches, returns and time in the foreground are tracked for you; events wait on the device until they are sent.

  • React Navigation, Expo Router
  • Queue survives restarts
  • No advertising ids

rabolic.init(options)

One call at app start.

Install the package with AsyncStorage, start it with your project’s publishable key, and track the events that matter. You don’t have to await init: calls made while it loads are kept and sent after the launch events. Or run npx rabolic init and it does the install, the file and the key for you.

  • Expo and the React Native CLI, iOS and Android
  • No native code of its own: works in Expo as it is
  • debug: true logs every call and response
  • Calls never throw into your app
import { rabolic } from '@rabolic/react-native'

// Once, at app start. Calls made before it finishes are kept.
void rabolic.init({
  projectKey: 'rb_pub_…',
  app: { version: '4.12.0', build: '412' },
})

rabolic.track('workout_started', { program_id: 'strength-30' })

rabolic.trackNavigation(ref)

Every screen, from the navigation you already use.

Hand the SDK your navigation container’s ref and every route change sends a $screen named after the route. It works with React Navigation and with Expo Router, which is built on it.

  • React Navigation: call it from onReady
  • Expo Router: useNavigationContainerRef() in the root layout
  • The same route twice in a row counts once
  • rabolic.screen() for anything outside a navigator
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native'
import { rabolic } from '@rabolic/react-native'

export function App() {
  const ref = useNavigationContainerRef()
  return (
    // A $screen for every route change, named after the route
    <NavigationContainer ref={ref} onReady={() => rabolic.trackNavigation(ref)}>
      {/* your navigators */}
    </NavigationContainer>
  )
}

trackLifecycle: true

Launches, returns and time in the app.

The SDK follows the app’s state on its own. A session starts at launch and again when the app comes back after more than 30 seconds in the background; time in the background never counts as active time.

Events are kept in AsyncStorage, so they survive restarts and offline periods, and go out in batches with retry and backoff, and whenever the app goes to the background.

Events the React Native SDK sends automatically
EventWhenProperties
$app_first_openFirst launch after install
$app_updateFirst launch on a new app.versionprevious_version
$app_openLaunch, and every return to the foregroundfrom_background
$app_backgroundThe app goes to the backgroundforeground_ms
$screenEach route change, with trackNavigationname, and context.screen_name

rabolic.trackDeepLink(url)

Know which link opened your app.

Pass the links that open the app to the SDK. It sends $deep_link with the link and the rb_aid your website added through appLink(). Linking the web visitor to the app user by that id isn’t built yet; identify() with the same user id joins them today.

  • linked_anonymous_id from the link’s rb_aid
  • Strip secrets such as magic-link tokens first: the URL is sent
How identity resolution works
links.ts
import { Linking } from 'react-native'
import { rabolic } from '@rabolic/react-native'

// The link that opened the app, and every link after
Linking.getInitialURL().then((url) => url && rabolic.trackDeepLink(url))
Linking.addEventListener('url', ({ url }) => rabolic.trackDeepLink(url))

// Sends $deep_link with the url, and linked_anonymous_id from rb_aid

the rabolic object

Calls you know from the web.

track, identify on login, reset on logout, super properties and consent work as in the web SDK, so shared code reads the same in your site and your app; screen() takes the place of page views.

  • Never collects advertising ids, the Android id or location
  • No form fields, clipboard or fingerprints
  • No App Tracking Transparency prompt needed
anywhere.ts
rabolic.track('workout_started', { program_id: 'strength-30' })

// A tab change that doesn't go through a navigator
rabolic.screen('Progress')

rabolic.identify('usr_8f2k1x9q', { plan: 'pro' })
rabolic.register({ app_theme: 'dark' })

// Consent
rabolic.setConsent('denied')

limits

The numbers.

Property values may be strings, numbers, booleans, null, arrays and objects, as in JSON.

React Native SDK limits
LimitValue
Event name1–200 characters, snake_case, not starting with $
Properties255 keys per level, nesting depth 5, keys up to 255 characters
One event32 KB (32,768 bytes of UTF-8 JSON). Larger events are dropped
Queue10,000 events, kept in AsyncStorage. When full, the oldest go first
Event ageEvents older than 7 days are dropped before sending
Batch500 events or 900 KB, every 15 seconds, at 20 queued events, and when the app goes to the background
RequestsOne at a time, 10 s timeout, backoff from 1 s to 5 min with jitter. Retry-After is honored

react native sdk faq

The React Native SDK, answered.

Does it work with Expo?

Yes. The SDK has no native code of its own; it needs only AsyncStorage, which Expo ships. Install both with npx expo install so the versions match your Expo SDK.

How are screens tracked?

Pass your navigation container ref to rabolic.trackNavigation(): React Navigation’s from onReady, or Expo Router’s useNavigationContainerRef() in the root layout. Every route change sends $screen with the route’s name. rabolic.screen() covers anything else.

What does it send on its own?

$app_first_open on the first launch, $app_update on the first launch of a new version, $app_open on every launch and return to the foreground, and $app_background with the time spent in the foreground. trackLifecycle: false turns them off.

When does a session start?

At launch, and when the app comes back after more than 30 seconds in the background. Time in the background never counts as active time.

What happens offline?

Events wait in a queue in AsyncStorage, up to 10,000, and are sent when the app is back online, with retry and backoff. Queued events survive the app being closed.

How do I connect the app to the same person on the web?

Call identify() with the same user id after sign-in in the app and on your website. Rabolic then joins the install and the browser into one person, with their earlier events.

Which key does it take?

The project’s publishable key (rb_pub_…). A secret key is refused, because it can send revenue and must never ship in an app.

Is there a native iOS or Android SDK?

Not yet; native Swift and Kotlin SDKs are planned. Apps built with React Native or Flutter are covered today.

Track your React Native app on iOS and Android.

Start a 3-day trial without a card. It begins with your first event, so you can set up the SDKs first.

  1. 1

    Create a project

    Sign up, name your project, and copy its publishable key.

  2. 2

    Add an SDK

    Web, React Native, Flutter or Node.js, or the HTTP API. Or run npx rabolic init.

  3. 3

    Watch the first event arrive

    It shows in live events within seconds, and your trial starts then.