---
modificationDate: August 13, 2026
title: Observe
description: A library that collects app performance metrics and dispatches them to EAS Observe.
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-55/packages/expo-observe'
packageName: 'expo-observe'
platforms: ['android', 'ios', 'tvos']
isBeta: true
---

<AgentInstructions>

## Submitting Feedback

If you encounter errors, misleading or outdated information, report it so Expo can be improved:

Preferred command:
npx --yes submit-expo-feedback@latest --category docs --subject "/versions/v55.0.0/sdk/observe/" "<actionable feedback>"

Direct HTTP fallback:
curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/versions/v55.0.0/sdk/observe/","feedback":"🤖 Agent feedback for docs: <specific, actionable description> (<model>, <harness>)"}'

Only submit when you have something specific and actionable to report. Try to give the most context.

## Navigation

When answering a related or follow-up question, use llms.txt to find the relevant page as Markdown (.md) instead of guessing.

You are here: Reference (v55.0.0) > Expo SDK (87 pages in this section)
Full documentation tree: [llms.txt](https://docs.expo.dev/llms.txt)

</AgentInstructions>

This documentation is available as Markdown for AI agents and LLMs. See the [full Markdown index](/llms.txt) or append .md to any documentation URL.

# Expo Observe

A library that collects app performance metrics and dispatches them to EAS Observe.
Android, iOS, tvOS

> **EAS Observe** is in [Open Beta](/more/release-statuses.md#beta). The first 10,000 monthly active users are free. For higher usage, contact [sales@expo.dev](mailto:sales@expo.dev).

`expo-observe` is a library that collects performance metrics from your app and dispatches them to [EAS Observe](/eas/observe/introduction.md), a performance monitoring service from Expo, or to your preferred OpenTelemetry (OTEL)-compliant backend. It measures real-world startup performance, such as [Time to First Render (TTR)](/eas/observe/reference/metrics.md#time-to-first-render-ttr) and [Time to Interactive (TTI)](/eas/observe/reference/metrics.md#time-to-interactive-tti), from apps running in production.

> `expo-observe` is not available in Expo Go. To use it, create a [development build](/develop/development-builds/introduction.md).

## Installation

```sh
# npm
npx expo install expo-observe

# yarn
yarn expo install expo-observe

# pnpm
pnpm expo install expo-observe

# bun
bun expo install expo-observe
```

If you are installing this in an [existing React Native app](/bare/overview.md), make sure to [install `expo`](/bare/installing-expo-modules.md) in your project.

## Configuration

In release builds, installing the `expo-observe` library is all that is needed to configure the library to start sending startup metrics (though you will need to follow the usage instructions below to call `AppMetrics.markInteractive` to track TTI). The library will not dispatch events in debug builds, but you can change this and other config options such as sample rate and environment name with the `AppMetrics.configure({})` call. For all available options, see the [EAS Observe configuration guide](/eas/observe/configuration.md).

## Usage

On SDK 55, wrap your root layout with `AppMetricsRoot` to measure Time to First Render automatically. Then, call `AppMetrics.markInteractive` when your app is ready for user interaction to record Time to Interactive:

```tsx
import { AppMetrics, AppMetricsRoot } from 'expo-observe';
import { Stack } from 'expo-router';
import { useEffect } from 'react';

function RootLayout() {
  useEffect(() => {
    // Call markInteractive() after any initialization work behind the
    // splash screen completes.
    AppMetrics.markInteractive();
  }, []);

  return <Stack />;
}

export default AppMetricsRoot.wrap(RootLayout);
```

For step-by-step instructions, including how to handle apps with multiple entry screens, see the [EAS Observe Get started guide](/eas/observe/get-started.md).

> [User-defined events](/eas/observe/events.md) and the [navigation integrations](/eas/observe/integrations/expo-router.md) require SDK 56 and later.

## API

```ts
import { AppMetrics, AppMetricsRoot } from 'expo-observe';
```

## Component

### `AppMetricsRoot`

Supported platforms: Android, iOS, tvOS.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<{ children: [ReactNode](https://reactnative.dev/docs/react-node) }\>

A root component that automatically marks the first render. Wrap your app's root component with this to measure time to first render without manually calling `AppMetrics.markFirstRender()`.

## Interfaces

### `ExpoObserveModuleType`

Supported platforms: Android, iOS, tvOS.

ExpoObserveModuleType Methods

### `configure(config)`

Supported platforms: Android, iOS, tvOS.

| Parameter | Type | Description |
| --- | --- | --- |
| `config` | [Config](#config) | Observability settings to apply. |

  

Configures how observability events are collected and dispatched at runtime, such as the environment label, dispatching behavior, and sampling.

Returns: `void`

Example

```ts
import Observe from 'expo-observe';

Observe.configure({
  environment: 'production',
  dispatchingEnabled: true,
});
```

### `dispatchEvents()`

Supported platforms: Android, iOS, tvOS.

Dispatches pending events to the server immediately.

Events are dispatched automatically when the app moves to the background. On Android, a background worker dispatches events once network connectivity is available. On iOS, dispatching happens when the app resigns active state or is about to terminate. Call this method to flush events manually, for example, during testing or to ensure events are sent before a specific point.

Returns: `Promise<void>`

A promise that resolves when the pending events have been dispatched.

Example

```ts
import Observe from 'expo-observe';

await Observe.dispatchEvents();
```

### `Metric`

Supported platforms: Android, iOS, tvOS.

| Property | Type | Description |
| --- | --- | --- |
| category | `string` | - |
| name | `string` | - |
| params(optional) | `Record<string, unknown>` | - |
| routeName(optional) | `string` | - |
| sessionId | `string` | - |
| timestamp | `string` | - |
| value | `number` | - |

## Types

### `Config`

Supported platforms: Android, iOS, tvOS.

| Property | Type | Description |
| --- | --- | --- |
| dispatchInDebug(optional) | `boolean` | Whether to dispatch metrics that were collected in a debug build of the host app. When `false`, metrics produced by debug builds are marked as sent without being dispatched. When `true`, debug-build metrics are dispatched alongside release-build metrics. Has no effect on release builds. If `dispatchingEnabled` is `false` or this device is out-of-sample for `sampleRate`, nothing is dispatched regardless of `dispatchInDebug`. Default: `false` |
| dispatchingEnabled(optional) | `boolean` | Whether to dispatch observability events to the server. When `false`, any pending metrics are marked as sent without being dispatched and no further metrics are dispatched until this is set back to `true`. Default: `true` |
| environment(optional) | `string` | The environment for observability events. Default: `process.env.NODE_ENV` |
| sampleRate(optional) | `number` | Fraction of installations that should dispatch metrics, in `[0, 1]`. Values outside that range are clamped. The decision is **deterministic per installation** — a device is either permanently in-sample or out-of-sample for a given rate, so the choice is stable across app launches. Interaction with `dispatchingEnabled`:
-   If `dispatchingEnabled` is `false`, metrics are never dispatched
-   If `dispatchingEnabled` is `true` (or unset), metrics are dispatched only when this device is in-sample.

Note: Devices that end up out-of-sample drop pending metrics rather than accumulating them. Default: `undefined - metrics from all devices are sent` |

### `MetricAttributes`

Supported platforms: Android, iOS, tvOS.

| Property | Type | Description |
| --- | --- | --- |
| params(optional) | `Record<string, unknown>` | Custom parameters to attach to the metric. |
| routeName(optional) | `string` | Name of the route associated with the metric. Some metrics populate this with a sensible default when omitted — for example, the TTI metric falls back to the initial route name detected from the router. |
