Installation guides
React Native & Expo
@metricraven/react-native records screen views, goals and identified users from your app. Events wait in a queue while the device is offline and are sent when it reconnects.
Set up
Allow your app in Settings
In your site's Settings, add your bundle ID (iOS) or package name (Android) under Mobile apps, for example
com.example.app. App events from IDs that aren't listed are rejected.Install the SDK
AsyncStorage is optional, but without it queued events are lost if the app is closed while offline.
terminalnpx expo install @metricraven/react-native @react-native-async-storage/async-storageCreate the client once
analytics.ts// analytics.ts import AsyncStorage from "@react-native-async-storage/async-storage"; import * as Application from "expo-application"; import { createMetricRaven } from "@metricraven/react-native"; export const analytics = createMetricRaven({ siteId: process.env.EXPO_PUBLIC_METRICRAVEN_SITE_ID!, appId: Application.applicationId ?? "com.example.app", // listed under Settings → Mobile apps appVersion: Application.nativeApplicationVersion ?? undefined, appBuild: Application.nativeBuildVersion ?? undefined, storage: AsyncStorage, // keeps the offline queue (and, with consent, the visitor ID) disabled: __DEV__, });Track screens
With Expo Router, track the route pattern from your root layout:
app/_layout.tsx// app/_layout.tsx import { Slot, useSegments } from "expo-router"; import { MetricRavenProvider, useExpoRouterTracking } from "@metricraven/react-native"; import { analytics } from "../analytics"; function ScreenTracking() { useExpoRouterTracking(useSegments()); // "/users/[id]", never the real ID return null; } export default function RootLayout() { return ( <MetricRavenProvider client={analytics}> <ScreenTracking /> <Slot /> </MetricRavenProvider> ); }With React Navigation, pass the helpers to your container. It records route names, not params:
App.tsx// App.tsx import { NavigationContainer, useNavigationContainerRef } from "@react-navigation/native"; import { MetricRavenProvider, trackNavigation } from "@metricraven/react-native"; import { analytics } from "./analytics"; export default function App() { const navigationRef = useNavigationContainerRef(); return ( <MetricRavenProvider client={analytics}> <NavigationContainer ref={navigationRef} {...trackNavigation(analytics, navigationRef)}> {/* your navigators */} </NavigationContainer> </MetricRavenProvider> ); }Send events and identify users
server.tsanalytics.track("cta_click", { source: "home" }); analytics.screen("Paywall"); // a screen view outside your navigator analytics.identify(user.id, { name: user.name, email: user.email, plan: "pro" }); analytics.reset(); // on logout analytics.setConsent(true); // from your consent prompt analytics.openedFromUrl(url); // utm_* from a deep link, for the next screen view // In components: const analytics = useMetricRaven(); useScreen("Settings");
Verify it works
Open the app on a device or simulator with disabled off. The screen appears in Realtime. Screens are listed under Pages as paths like /Home or /users/[id], and your app ID appears under Hostnames.
Client
| Call | Notes |
|---|---|
| screen(name, props?) | A screen view. Names like "Settings" become the path /Settings. |
| track(name, props?) | A custom goal, attributed to the current screen. Up to 10 properties. |
| identify(userId, traits?) | Links this device's visitor to your user ID, with optional name, email and up to 10 custom traits. |
| reset() | On logout. Forgets identify state and, with consent, starts a new visitor ID. |
| setConsent(granted) | Grants or withdraws storage consent. Withdrawing also removes the ID from queued events. |
| openedFromUrl(url) | Reads utm_* parameters from a deep link and attaches them to the next screen view. |
| flush() | Sends the queue now. Runs automatically when the app returns to the foreground or goes to the background. |
| getVisitorId() / onVisitorId() | The current visitor ID, and a listener for changes. |
| Option | What it does |
|---|---|
| siteId, appId | Required. appId must be listed under Mobile apps. |
| appVersion, appBuild | Shown on events and visitor profiles. Read them from expo-application or react-native-device-info. |
| storage | AsyncStorage. Persists the queue and, with consent, the visitor ID. |
| consent | Set true when the user has already allowed analytics storage. |
| apiHost / endpoint | Where events go. Defaults to https://metricraven.com/api/v1/collect. |
| maxQueueSize, maxEventAgeMs | Defaults to 500 events and 7 days. Older or extra events are dropped. |
| disabled | Turns tracking off, for example in development. |
Consent and visitor IDs
The app follows the same rules as the website tracker. Until you call setConsent(true) (or pass consent: true), nothing that identifies the device is stored. The server derives a daily visitor ID from the network address and the app's user agent. Raw IP addresses are not kept. With consent, a random ID is kept in storage, so sessions on different days connect. Granting consent also relabels today's events from that device.
Offline queue and retries
Events are sent one at a time, in order. Network errors, timeouts, rate limits and server errors are retried with growing waits, up to 5 minutes, and Retry-After is respected. Rejected events are dropped instead of retried. That covers invalid data, an app ID that isn't listed, an unknown site, or paused tracking. Events replayed more than 5 minutes after they happened are recorded at the time they arrive.
Details
- App traffic is identified by your app ID because native requests have no web page or browser origin. A browser can't use this to send data as your app: browser requests always carry an origin, and those are checked against your domains.
- Like the website tag, the site ID and app ID aren't secrets. The allowlist keeps out misconfigured and casual traffic, not a determined forger. For verified events, use server events or server identify.
- Expo Router: use
useSegments()rather thanusePathname(), so IDs in URLs (like/users/42) don't show up in reports. - Purchases inside the app: see RevenueCat and send the same user ID you pass to
identify. @metricraven/react-native/coreexports the client without React or react-native imports, for tests and other JavaScript runtimes.