EAS Observe Expo Router integration overview
EAS Observe ships an opt-in integration for Expo Router that collects per-route metrics tagged with the route pattern. This lets you compare navigation performance by route in the dashboard instead of looking only at app-wide aggregates.
Expo Router integration SDK requirement
The Expo Router integration for EAS Observe is available on SDK 56 and later. On earlier SDKs, expo-observe still tracks app-wide metrics, but per-route navigation events are not emitted.
Enable Expo Router integration in EAS Observe
Call Observe.configure() with the 'expo-router' integration flag at module scope, before any screen mounts: Observe.configure({ integrations: { 'expo-router': true } }). The integration must be enabled before mount and cannot be toggled at runtime. Calling configure() after the app has mounted, or toggling the flag mid-session, throws an error.
useObserve hook for per-route metrics
Use the useObserve() hook to get a markInteractive callback that is automatically scoped to the current route. The emitted event is tagged with the screen's route pattern. If the integration is disabled or expo-router is not installed, useObserve() falls back to the global Observe.markInteractive.
Filter sensitive URL parameters in Expo Router integration
Available in SDK 57 and later. Pass filtered parameter keys to filteredParams in Observe.configure(): Observe.configure({ integrations: { 'expo-router': { filteredParams: ['userId', 'token'] } } }). The integration removes filtered keys from routeParams, and the event omits url and includes urlHidden: true instead. routeName is not affected because it is a pattern and never contains parameter values.
cold_ttr metric definition
The cold_ttr metric measures time from when a navigation action is dispatched to when the destination screen first becomes focused. For the very first focus after app launch, the measurement is taken from when the JS bundle is loaded, and the event includes isAppLaunch: true. Emitted at most once per screen instance within a session.
cold_ttr event parameters
The cold_ttr event includes: routeName (string, route pattern like '/(tabs)/sessions/[sessionId]'), url (string, resolved pathname), urlHidden (boolean, present as true when url is omitted because a parameter was filtered), routeParams (object, resolved route params), isAppLaunch (boolean, true when measured against process start, false for subsequent navigation).
warm_ttr metric definition
The warm_ttr metric measures the same as cold_ttr, but for screens that were already rendered before focus, typically because they were preloaded via Link prefetch or the user navigated back to them.
warm_ttr event parameters
The warm_ttr event includes: routeName (string, route pattern), url (string, resolved pathname), urlHidden (boolean, present as true when url is omitted because a parameter was filtered), routeParams (object, resolved route params).
tti metric definition
The tti (time to interactive) metric measures time from when a navigation action is dispatched to when markInteractive() is called on the destination screen. Only the first call per navigation is recorded, so it is safe to call markInteractive() multiple times.
tti event parameters
The tti event includes: routeName (string, route pattern), url (string, resolved pathname), urlHidden (boolean, present as true when url is omitted because a parameter was filtered), routeParams (object, resolved route params), and any custom params passed via markInteractive({ params: { ... } }).
View navigation metrics in EAS Observe dashboard
In the dashboard, open your project, navigate to Observe, and select the Navigation tab. It shows per-route navigation timings with cold and warm time to first render and time to interactive.
CLI commands for navigation metrics
Use eas observe:routes to view navigation metrics grouped by route name. Use eas observe:routes --metric cold_ttr --route-name "/(tabs)/sessions/[sessionId]" to filter to specific metrics or routes. Run eas observe:routes --help for the full list of flags (time range, platform, app version, and more).
routeName is a pattern, not a resolved URL
routeName in EAS Observe metrics is a pattern (for example, /(tabs)/sessions/[sessionId]), not a resolved URL like /sessions/abc. This keeps metrics stable across distinct param values so the dashboard buckets them together. Resolved values are still available on the event via url and routeParams.
router.prefetch does not seed cold_ttr or warm_ttr
Calls to router.prefetch() do not count as a user navigation and never seed a cold_ttr or warm_ttr measurement. The next user-driven navigation to that route emits warm_ttr because the screen has already rendered.
Integration requires expo-router installed at runtime
The Expo Router integration for EAS Observe only activates if expo-router is installed at runtime. If it is not installed, useObserve() and ObserveRoot continue to work but no per-route navigation metrics are emitted.
markInteractive outside screen component error
If markInteractive() logs 'Calling markInteractive on unmounted screen' or 'No metadata available for the current screen', the call ran outside a screen component or after unmount. Move the call into a useEffect inside the screen component.