SDK reference
Every component, hook and method in @riveora/react-native.
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.
<RiveoraProvider
projectKey="pk_your_project_key"
storage={new AsyncStorageAdapter(AsyncStorage)}
appVersion={Constants.expoConfig?.version}
consent="granted"
>
{children}
</RiveoraProvider>| Prop | Type | Description |
|---|---|---|
projectKeyrequired | string | Your public project key. Starts with pk_. |
endpoint | string | Where events are sent. Only set it if your app’s Install page shows an endpoint line.Default: 'https://ingest.riveora.com' |
storage | Storage | Where 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' |
appVersion | string | Your 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. |
autocapture | boolean | AutocaptureOptions | Automatic taps, rage taps, crashes, and failed or slow requests. See options. Default: true |
beforeSend | (event) => event | null | Called 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. |
screenshots | boolean | Pictures of each screen for the dashboard's tap map, taken in development builds only. Needs react-native-view-shot. See screen pictures.Default: true |
backgroundTimeoutMs | number | Coming 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' |
transport | Transport | Replace how batches are sent. For tests or custom networking. |
logger | Logger | Replace 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 setup | What 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 Native | appVersion={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
| Setting | Value |
|---|---|
| Batch size | Sent when 20 events are waiting; at most 100 events and 256 KB per request |
| Batch interval | Every 10 seconds, and when the app goes to the background |
| Visits | Every 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 queue | Up to 500 events are kept; the oldest are dropped beyond that |
| Before startup | Events from before the visit starts, like the first screen, are kept (up to 100) and sent once it does |
| Retries | Network 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 limits | Your 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 cleaning | Only 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.
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.
<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.
<RiveoraLabel label="Plan: Pro"><PlanCard plan={pro} /></RiveoraLabel>TrackedPaywall
| Prop | Type | Description |
|---|---|---|
paywallId | string | Your name for the paywall. Not needed with offering. |
offering | { identifier } | The RevenueCat offering shown. Its identifier becomes the paywall’s name. |
visiblerequired | boolean | Open when it becomes true, close when it becomes false. Unmounting while open closes it with the reason unmounted. Renders nothing while false. |
source | string | Where the user was when it opened. |
trigger | string | Why it opened. |
onCloseReason | () => string | undefined | Return 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.
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).