new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Expo · EAS · all subjects

eas observe

45 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Metrics not appearing in EAS Observe dashboard

If metrics are not showing in the EAS Observe dashboard, first ensure you have created a new build after installing expo-observe, because metrics are only collected from builds that include the library. Second, verify you are viewing the correct project in the EAS dashboard. Third, if testing in a debug build, confirm that dispatchInDebug is set to true via configure(). See the Enable metrics in development configuration documentation.

Time to first render metric not showing in EAS Observe

To fix the time to first render metric not appearing, verify that your root layout is wrapped with the root HOC. For SDK 56 and later, import ObserveRoot from expo-observe and wrap your RootLayout with ObserveRoot.wrap(RootLayout). For SDK 55, import AppMetricsRoot from expo-observe and wrap your RootLayout with AppMetricsRoot.wrap(RootLayout).

Time to interactive metric requires manual instrumentation

The time to interactive metric in EAS Observe requires manual instrumentation. For SDK 56 and later, call markInteractive() from useObserve() after your splash screen is hidden and verify the call is being executed by adding a console.log. For SDK 55, call AppMetrics.markInteractive() after your splash screen is hidden and verify execution with console.log.

Migrate from expo-eas-observe to expo-observe

To migrate from expo-eas-observe to expo-observe: (1) Replace the package by running 'npx expo install expo-observe' and 'npm uninstall expo-eas-observe'. If previously installed separately, also uninstall expo-eas-client. (2) Update imports from 'import AppMetrics from expo-eas-observe' to 'import { AppMetrics } from expo-observe'. (3) Replace manual markFirstRender() calls with the root HOC wrapper instead. (4) Create a new build by running 'eas build'.

SDK 55 root HOC for time to first render metric

For SDK 55, use the following code pattern to wrap your root layout for automatic time to first render measurement: import { AppMetricsRoot } from 'expo-observe'; function RootLayout() { return (/* your layout */); } export default AppMetricsRoot.wrap(RootLayout);

New build required after installing expo-observe

After installing the expo-observe library, you must create a new build of your app for metrics to be collected. Metrics are only collected from builds that include the expo-observe library.

Session concept in EAS Observe

A session starts when the app process is launched and ends when the app process is terminated. Each session has a unique identifier and contains all metrics collected during that app launch.

User concept in EAS Observe

A user is identified by an anonymous ID that is unique per app installation. This ID is generated when the app is first installed, persists across app updates, and is reset if the user uninstalls and reinstalls the app. The ID is not Personally Identifiable Information (PII), allowing metrics to be tracked across multiple sessions for the same user without collecting personal data.

Cold launch time metric definition

Cold launch time measures the time from process creation to when the system has finished allocating memory, starting a fresh runtime environment, loading the app's code and resources from disk, and initializing its components before rendering the UI. This is a native-only metric that includes React Native runtime initialization but is not affected by JavaScript code. Cold launches typically occur after a fresh install, app upgrade, device reboot, or when the OS has killed the app to reclaim memory. This metric is collected automatically. Recommendation: under 1.5s.

Warm launch time metric definition

Warm launch time measures the duration when the OS already has the app process in memory and only needs to bring it back to the foreground and recreate the view hierarchy. Unlike a cold launch, most native resources and services are already in memory, making this type of launch significantly faster. Apps cannot pre-warm themselves; the OS decides which processes stay in memory based on system pressure and recent use. This metric is collected automatically. Recommendation: under 0.5s.

Bundle load time metric definition

Bundle load time measures the duration of loading the JavaScript bytecode and evaluating it. This starts when the bundle begins loading and ends when the bundle finishes evaluating, before runApplication is called. This metric is collected automatically. Recommendation: under 0.3s.

Time to first render (TTR) metric definition

Time to first render measures the time from when the app finishes native launching to when the root React component first renders on the screen. This is the moment actual content is rendered by React, after the splash screen is hidden. The goal for every app should be to show something meaningful as fast as possible, even if it's a skeleton loading screen. This metric is collected automatically when you wrap your root layout with the root HOC. Recommendation: under 2s including the cold launch time.

Time to interactive (TTI) metric definition

Time to interactive measures the time between the warm/cold launch and when the user can actually tap, scroll, and interact with the app in other ways. It is the most important startup metric because it is what users perceive as 'the app is ready'. This metric is not reported automatically. To start measuring it, call markInteractive() once the screen is ready for user interaction, for example in a useEffect that runs after your initial data has loaded. Only the first call per launch is recorded, so it is safe to call it multiple times. If you use expo-router, the metric's event automatically includes the current route name. Recommendation: under 3s including the cold launch time.

TTI markInteractive() usage for SDK 56 and later

To mark the app as interactive in SDK 56 and later, call markInteractive() from the useObserve() hook inside a component.

TTI markInteractive() usage for SDK 55

To mark the app as interactive in SDK 55, call AppMetrics.markInteractive() from anywhere in your app.

What makes an app interactive

An app is considered interactive when all of the following are true: content is rendered on the screen (not just a splash or skeleton), touch handlers are attached and responsive, and navigation is functional.

TTI automatic event params

Each TTI event includes the following automatic params: expo.frameRate.slowFrames (count of frames that took 17ms or longer to render), expo.frameRate.frozenFrames (count of frames that took 700ms or longer to render), expo.frameRate.totalDelay (total accumulated time in seconds all frames exceeded their target duration), expo.device.lowPowerMode (boolean whether Low Power Mode on iOS or Battery Saver on Android was active), expo.device.batteryLevel (number 0–1 representing fractional battery charge, omitted when OS does not report), expo.device.batteryCharging (boolean whether device was plugged in or wirelessly charging), expo.device.thermalState (string: one of nominal, fair, serious, critical, unknown), expo.network.connected (boolean whether device had internet-capable network at TTI), and expo.network.type (string: one of wifi, cellular, ethernet, none, other, unknown).

TTI custom event params with SDK 56 and later

To attach custom params to the TTI event in SDK 56 and later, import useObserve from expo-observe, call const { markInteractive } = useObserve(), then call markInteractive({ params: { /* your custom params */ } }). You can also override the route name with the routeName property. Param values can be strings, numbers, booleans, or other JSON-serializable values.

TTI custom event params with SDK 55

To attach custom params to the TTI event in SDK 55, import AppMetrics from expo-observe and call AppMetrics.markInteractive({ params: { /* your custom params */ }, routeName: '/route' }). Param values can be strings, numbers, booleans, or other JSON-serializable values.

ObserveInteractiveMarker component for TTI

Instead of calling markInteractive() from an effect, you can render the ObserveInteractiveMarker component (available in SDK 56 and later) at the point your screen becomes interactive, such as once its initial data has loaded. It calls markInteractive() once when it mounts and renders nothing. The marker fires only once on mount, so its params are read from the first render. Changing them afterward has no effect. If you need to attach params that are only known later, call useObserve().markInteractive(...) directly instead.

Sampling in EAS Observe

By default, all installations dispatch their metrics. To dispatch from a fraction of installations instead, set sampleRate when calling configure(). The decision is deterministic per installation, so an installation is consistently in-sample or out-of-sample across app launches.

Environment grouping in EAS Observe

All metrics are grouped by environment. The environment value is derived from process.env.NODE_ENV by default (falling back to 'production' if unset), or can be overridden via configure({ environment }). The environment is a metadata tag attached to each metric and does not affect whether metrics are dispatched.

Debug builds handling in EAS Observe

Metrics collected from debug builds are dropped before dispatching unless dispatchInDebug is set to true via configure(). A build is treated as a debug build if either the native app is a debug build or the JS bundle is a development bundle (__DEV__ is true). This detection is independent of the environment value.

Disabling dispatching in EAS Observe

You can disable all dispatching globally using configure({ dispatchingEnabled: false }). While disabled, any pending metrics are dropped without being dispatched and no further metrics are dispatched until it is set back to true.

Cold launch time improvements

To improve cold launch time: remove unused native modules, avoid static initializers (+load methods in Objective-C, static constructors in C++), and native modules or config plugins that add them, keep the app's memory and CPU usage low so the OS does not kill the process while in the background (which makes subsequent launches warm instead of cold), and if you use expo-updates with a non-zero fallbackToCacheTimeout, the app launch is blocked waiting for an update check so keep this value at 0 (default), or set checkOnLaunch to NEVER or ERROR_RECOVERY_ONLY to avoid delaying cold launches.

Warm launch time improvements

To improve warm launch time: remove unused native modules and reduce the number of views in the view hierarchy because the OS has to recreate the view tree on warm launch, so a deeply nested or bloated tree takes longer to restore.

Bundle load time improvements

To improve bundle load time: reduce the bundle size by using tree shaking (enabled by default as of Expo SDK 54) and following the rules that help Metro strip unnecessary code, analyzing your JavaScript bundle to remove unused and large dependencies, lazy-loading large screens and components with React.lazy(), and avoiding blocking the JavaScript thread in the top-level scope (don't do heavy computations and defer any synchronous I/O operations like storage reads and writes).

Time to first render improvements

To improve time to first render: reduce bundle load time, avoid synchronous I/O operations (storage reads and writes), avoid blocking on network requests, keep the initial render tree small (defer heavy components), use a lightweight screen as the initial route, and minimize useEffect and useLayoutEffect chains that block rendering.

TTI measurement accuracy improvements

To improve TTI measurement accuracy, call markInteractive() only after the screen's content is loaded and touch handlers are active, not just on component mount. If your screen fetches data before becoming usable, place the call after the data is ready.

TTI improvements

To improve TTI: reduce time to first render, avoid waterfall data fetches before showing interactive content, optimize initial network requests, avoid rendering large lists (use FlashList or LegendList), reduce heavy work that may block the JavaScript thread and interactions (I/O operations, state hydration, JSON parsing), and if possible, show cached or local data first.

TTI event interpretation

Interpret TTI events as follows: High TTI + low total delay indicates startup is slow but smooth, so optimize what's blocking the launch sequence (bundle size, data fetching, initialization chains). High TTI + high total delay + many slow frames indicates main thread contention, so offload work and simplify the initial render tree. High TTI + high delay + frozen frames indicates something is blocking hard, so look for synchronous I/O, large JSON parsing, or blocking API calls.

Duration metrics reporting unit in EAS Observe

All duration metrics are reported in seconds.

EAS Observe is a production performance monitoring service

EAS Observe is a performance monitoring service from Expo that tracks how your app performs in production. It gives visibility into real-world startup times, rendering performance, and user experience across different devices, networks, and conditions. It is currently in Open Beta, with the first 10,000 monthly active users free.

EAS Observe focuses on production performance, not development

EAS Observe focuses on production performance where performance characteristics differ significantly from development. Traditional development-time profiling tools show how your app performs on your machine, whereas EAS Observe shows how it performs for real users.

Install expo-observe library for EAS Observe

The expo-observe library is installed using npx expo install expo-observe (npm), yarn expo install expo-observe (yarn), pnpm expo install expo-observe (pnpm), or bun expo install expo-observe (bun).

Wrap root layout with AppMetricsRoot or ObserveRoot component

Wrap your root layout with the AppMetricsRoot component for SDK 55, or the ObserveRoot component for SDK 56 and later. Call markInteractive() when your app is ready for user input.

EAS Observe key features and capabilities

EAS Observe provides production performance data tracking startup times, render performance, and bundle load times from real user sessions. It enables release comparison to see how metrics change between app versions and OTA updates, session investigation to drill into individual user sessions, user-defined events logging via Observe.logEvent, and CLI and dashboard access for querying and viewing metrics.

EAS Observe metrics tracked

EAS Observe focuses on startup metrics: cold launch time, warm launch time, time to first render, time to interactive, and bundle load time. Users can also log custom signals as user-defined events.

EAS Observe platform support

EAS Observe supports Android and iOS. Metrics are collected from production builds and can be filtered by platform in both the dashboard and CLI.

EAS Observe is not available in Expo Go

EAS Observe is not available in Expo Go. It relies on the expo-observe native library which is not included in Expo Go. To use EAS Observe, you must create a development build or a production build.

EAS Observe does not collect personally identifiable information

EAS Observe does not collect personally identifiable information. Users are identified by an anonymous ID that is unique per app installation. This ID is not personally identifiable and is reset if the user uninstalls and reinstalls the app.

Offline metrics handling in EAS Observe

Metrics collected while offline are stored locally on the device. They are automatically dispatched when the app moves to the background and connectivity is available. You can also flush events manually using dispatchEvents().

Debug build metrics in EAS Observe

By default, metrics collected from debug builds are not dispatched. To dispatch metrics during development for testing, set dispatchInDebug to true via the configure() function.

EAS Observe metric data retention

Metric data is retained for a minimum of 60 days.

When to use EAS Observe

EAS Observe should be used for monitoring app startup performance in production, comparing performance across releases and OTA updates, investigating slow sessions on specific devices, querying performance metrics from the CLI, and tracking user-defined events from your app. EAS Observe is not intended for development-time profiling and debugging (use React Native DevTools instead) or crash reporting and error tracking (use services like Sentry or BugSnag instead).

Give your agent this brain