Track screens
Record a $screen event for every screen with Expo Router, React Navigation or manual calls.
The SDK records a $screen event each time a new screen appears. Each event names the previous
screen and how long the user stayed there, so one event describes a whole transition. Tracking is
on by default; connect it to your router.
Expo Router
Render ScreenTracking once in the root layout, inside the provider:
import { Stack } from "expo-router";
import { ScreenTracking } from "@voidhash/react-native/expo-router";
import { voidhash } from "../src/lib/voidhash";
export default function RootLayout() {
return (
<voidhash.Provider>
<ScreenTracking />
<Stack />
</voidhash.Provider>
);
}The screen name is the file route, such as /(tabs)/item/[id], and the path is the pathname, such
as /item/42. useExpoRouterScreenTracking() is the same as a hook.
React Navigation
Pass the handlers from useScreenTracking to your navigation container:
import { NavigationContainer } from "@react-navigation/native";
import { useScreenTracking } from "@voidhash/react-native/react-navigation";
export function AppNavigation() {
const screenTracking = useScreenTracking();
return (
<NavigationContainer
ref={screenTracking.ref}
onReady={screenTracking.onReady}
onStateChange={screenTracking.onStateChange}
>
<RootNavigator />
</NavigationContainer>
);
}Call it in a component rendered inside <voidhash.Provider>. The screen name is the focused route's
name and the path is the chain of navigators, such as /Tabs/Home/Feed. If you already have a
container ref, pass it with useScreenTracking({ ref }) and call onReady and onStateChange
from your own callbacks.
Manual screens
For screens a router doesn't see, such as onboarding pager pages, call screen(). Each call records
a new screen.
voidhash.client.screen("Onboarding step 2", { step: 2 });Event properties
| Property | Meaning |
|---|---|
$screen_name | Stable screen identity, without IDs. |
$screen_path | Concrete location, with dynamic segment values. |
$screen_title | The screen's title, when the router exposes one. |
$previous_screen_name, $previous_screen_path | The screen the user came from; null on the first screen. |
$previous_screen_duration_ms | Time spent on the previous screen, background time included. |
$screen_source | expo-router, react-navigation or manual. |
$screen_params | Route params, when includeParams is on. |
A screen is recorded once when it appears; returning from the background doesn't record it again.
The same route with different params, such as /item/1 then /item/2, records both.
Options
import { createVoidhashClient } from "@voidhash/react-native";
export const voidhash = createVoidhashClient("vh_pk_...", {
screenTracking: {
includeParams: false,
mapScreen: (view) => (view.name.startsWith("/debug") ? null : view),
},
});| Option | Default | Description |
|---|---|---|
enabled | true | false turns off the integrations and screen(). |
includeParams | false | Adds route params as $screen_params, string values, at most 20 keys. Off because params often hold IDs. |
mapScreen | none | Renames a screen, or drops it by returning null. If it throws, or returns a screen whose identity, name or path isn't a string, the screen is recorded unchanged and HOST_CALLBACK_FAILED is reported. |
To stop storing $screen for a project without a release, turn it off in Settings → Events.
Next steps
Something wrong or missing on this page? Tell us by email or on Discord.