Reference

SDK reference

Every component, hook and method in @riveora/react-native.

8 min readSDK 0.5.0

Everything exported by @riveora/react-native. Expo Router support lives in @riveora/react-native/expo-router.

RiveoraProvider

Wrap your app once, at the root. It starts the SDK, tracks visits and app state, and enables automatic capture.

tsx
<RiveoraProvider
  projectKey="pk_your_project_key"
  storage={new AsyncStorageAdapter(AsyncStorage)}
  appVersion={Constants.expoConfig?.version}
  consent="granted"
>
  {children}
</RiveoraProvider>
PropTypeDescription
projectKeyrequiredstringYour public project key. Starts with pk_.
endpointstringWhere events are sent. Only set it if your app’s Install page shows an endpoint line.
Default: 'https://ingest.riveora.com'
storageStorageWhere the anonymous ID and event queue are kept. Pass new AsyncStorageAdapter(AsyncStorage), or every launch looks like a new user.
Default: in-memory
consent'granted' | 'denied' | 'unknown'Events are only recorded and sent while granted. While unknown, events saved earlier wait on the device; denied deletes them. See Privacy & consent.
Default: 'unknown'
appVersionstringYour app version, shown on user profiles and visits and used by “Did my fix work?”. Not detected automatically, so pass it yourself. If iOS and Android are numbered differently, use Platform.select. Versions are always compared per platform.
autocaptureboolean | AutocaptureOptionsAutomatic taps, rage taps, crashes, and failed or slow requests. See options.
Default: true
beforeSend(event) => event | nullCalled with every event just before it’s queued, after the SDK’s own cleaning. Return the event (changed or not) to keep it, or null to drop it. If it throws, the event is dropped, so a failing filter never lets an event through unfiltered. Anything it adds isn’t cleaned again.
screenshotsbooleanPictures of each screen for the dashboard's tap map, taken in development builds only. Needs react-native-view-shot. See screen pictures.
Default: true
backgroundTimeoutMsnumberComing back to the app after longer than this (in milliseconds) starts a new visit. See Visits.
Default: 120000
logLevel'silent' | 'error' | 'warn' | 'info' | 'debug'How much the SDK logs to the console.
Default: 'warn'
transportTransportReplace how batches are sent. For tests or custom networking.
loggerLoggerReplace the console logger.

App version

The SDK doesn’t read your app’s version by itself, so pass it in. Every event is then tagged with it, and Riveora can tell you whether a problem went away in a new release: on each problem’s Did my fix work? card, on a screen’s page in Why people leave under By app version, and on user profiles.

Your setupWhat to pass
Expo (managed or development build)appVersion={Constants.expoConfig?.version} with import Constants from 'expo-constants'. This is the version in your app.json.
Bare React NativeappVersion={DeviceInfo.getVersion()} from react-native-device-info, or a string you keep in sync with your release.

Bump the version for each release you want to compare. Events sent before you add appVersion stay “Not reported”; the version can’t be filled in afterwards.

Built-in behavior

SettingValue
Batch sizeSent when 20 events are waiting; at most 100 events and 256 KB per request
Batch intervalEvery 10 seconds, and when the app goes to the background
VisitsEvery time someone opens the app is a new visit: a launch, or coming back after more than 2 minutes away. A short trip to another app stays in the same visit. See Visits
Offline queueUp to 500 events are kept; the oldest are dropped beyond that
Before startupEvents from before the visit starts, like the first screen, are kept (up to 100) and sent once it does
RetriesNetwork and server errors are retried with a growing, randomly spread wait (2 seconds up to 2 minutes). When the server is busy or a limit is reached, the SDK waits as long as its Retry-After says, up to 10 minutes. An event the server can’t accept is dropped on its own (development builds log why); the rest of the batch is stored
Event limitsYour plan’s monthly events (all apps together) and a daily limit per app: 10,000 on Starter, 100,000 on Pro (UTC day). Past a limit the SDK keeps the latest events on the device and checks back about every 10 minutes
Property cleaningOnly plain values are sent, at most 50 per event. Keys that name a secret or personal detail (password, token, email, phone, pin, api_key, first_name…) and values that look like an email, phone number, card number, IBAN, token or API key are dropped, on the device and again by the server. See Custom events

Screen trackers

ExpoRouterTracker

Import from @riveora/react-native/expo-router. Props: screenAlias, ignoreScreens, reportScreens, extraScreens. See Expo Router.

ReactNavigationTracker

Props: navigationRef (required), screenAlias, ignoreScreens, reportScreens, extraScreens. See React Navigation.

The Riveora object

A global API you can call from anywhere. It never throws into your app. Calls made before the provider mounts (at startup, or in background code such as a push notification handler on Android) wait in memory, up to 100, and are sent in order once the visit starts. They’re dated no earlier than the start of that visit.

tsx
import { Riveora } from '@riveora/react-native';

Riveora.identify(userId)

Links this device to your own user ID, up to 120 characters (numbers are sent as text). Returns a promise that never rejects: an empty or too-long ID, an email address or a phone number written with a + or spaces is ignored with a warning. A different user ID than before starts a new person and a new visit. See Identifying users.

Riveora.reset()

Starts a fresh anonymous ID and a new visit, and forgets the identified ID. Call it on sign-out. Events already waiting are still sent, as the person who made them. If the same user ID is identified again within 30 seconds, before anything else is recorded, the reset is undone.

Riveora.setConsent(state)

'granted', 'denied' or 'unknown'. Anything other than granted stops recording and sending. 'unknown' keeps events saved earlier on the device; 'denied' deletes them. In development builds, the screen list and screen pictures are also only sent while consent is 'granted'.

Riveora.track(name, properties?)

Sends a custom event. See Custom events for naming and limits.

Riveora.screen(name, properties?)

Marks a screen as shown, for screens your navigation tracker can’t see. Later events are tagged with it until the next screen.

Riveora.onboarding

start(flowId), stepViewed(flowId, stepId, stepIndex) and complete(flowId?). Each accepts optional properties. See Onboarding.

Riveora.paywall

open({ paywallId?, offering?, source?, trigger?, properties? }) returns a visit ID. Pass offering (a RevenueCat offering) to name the paywall after it, or paywallId for your own name; close(visitId, { reason?, properties? }) ends it. See Paywalls.

Riveora.flush()

Sends queued events immediately instead of waiting for the next batch. Returns a promise.

Riveora.diagnostics()

Returns { queueSize, consent, sessionId, anonymousId }. Useful when debugging.

Components and hooks

RiveoraIgnore

Taps on anything inside it are never recorded, however deep, and its text is never used to label a button around it. Screen pictures in development builds still show it.

tsx
<RiveoraIgnore><AccountDetails /></RiveoraIgnore>

RiveoraLabel

Gives taps inside it the label you choose, for menus, plan cards and options built from a list, which get no automatic text label. Adds no view. A label with an email address or a token isn’t sent. See Naming an element yourself.

tsx
<RiveoraLabel label="Plan: Pro"><PlanCard plan={pro} /></RiveoraLabel>

TrackedPaywall

PropTypeDescription
paywallIdstringYour name for the paywall. Not needed with offering.
offering{ identifier }The RevenueCat offering shown. Its identifier becomes the paywall’s name.
visiblerequiredbooleanOpen when it becomes true, close when it becomes false. Unmounting while open closes it with the reason unmounted. Renders nothing while false.
sourcestringWhere the user was when it opened.
triggerstringWhy it opened.
onCloseReason() => string | undefinedReturn the close reason, e.g. 'purchased'.

usePaywallTracking(input)

Takes { paywallId?, offering?, source?, trigger? } and returns { visitId, open, close }. Closes automatically, with the reason unmounted, if the component unmounts while it’s open.

tsx
const paywall = usePaywallTracking({ paywallId: 'main_offer', source: 'home' });

useEffect(() => {
  if (visible) paywall.open();
  else paywall.close('dismissed');
}, [visible]);

trackRevenueCatPaywall(present, input?)

Calls present (e.g. () => RevenueCatUI.presentPaywall({ offering })), records the visit, and returns RevenueCat’s result unchanged. input takes { offering?, paywallId?, source?, trigger? }. Results are recorded as purchased, restored, dismissed or presentation_failed; NOT_PRESENTED records nothing. See Paywalls.

useRevenueCatPaywallTracking(input)

For the <RevenueCatUI.Paywall> component. Takes { offering?, paywallId?, source?, trigger? } plus any of the component’s callbacks, and returns those callbacks with tracking added. Spread the result onto the component. The visit opens while the component is mounted and closes on onDismiss or unmount.

useScreenVisibility(screen, options?)

Low-level hook the trackers are built on. Records screen_viewed when screen changes and screen_visibility_ended when it goes away. Pass { paused: true } while an overlay covers the screen. Returns the current visit ID.

useRiveoraClient()

Returns the underlying client inside the provider, for advanced integrations.

AsyncStorageAdapter

Wraps @react-native-async-storage/async-storage for the storage prop: new AsyncStorageAdapter(AsyncStorage).

Something unclear or missing? Email us and we’ll improve this page.
SDK reference · Riveora Docs