All skills
expo avatar

/eas-observe

@948115e official
by expoexpo/skills2.6k stars
156

EAS service (paid). Use for anything related to EAS Observe - adding `expo-observe` to an Expo project (AppMetricsRoot/ObserveRoot HOC, markInteractive and ObserveInteractiveMarker, the useObserve hook, the Expo Router / React Navigation integrations for per-route metrics, user-defined events via `Observe.logEvent`, error reporting via ObserveErrorBoundary and `Observe.reportError`, and runtime config such as sampleRate and dispatchInDebug), querying via the EAS CLI (`eas observe:metrics-summary`, `observe:metrics`, `observe:routes`, `observe:events`, `observe:session`, `observe:versions`), interpreting the resulting metrics (cold/warm launch, TTR, TTI, navigation cold/warm TTR, update download, and the TTI frameRate/device/network params for triaging slow startups), or shipping an Observe integration inside a third-party package.

Use this Skill: https://skilld.dev/gh/expo/skills/eas-observe

This session only. Nothing lands on disk.

referencesqueries.md

≈4.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

EAS Observe CLI

EAS Observe collects app performance telemetry and custom events from Expo apps and exposes them through six EAS CLI commands. Pass the --help flag to any command for the latest API — the flags below were verified against eas-cli 21.8.0.

Source: https://docs.expo.dev/eas/observe/eas-cli/ — the canonical CLI page. This reference adds table layouts, JSON output shapes, and pagination details that the docs page does not cover.

Commands Overview

Command Purpose
eas observe:metrics-summary Per-version statistical aggregates for startup and navigation metrics (median, p90, etc.)
eas observe:metrics Individual metric samples ordered by value or timestamp (paginated)
eas observe:routes Per-route statistical aggregates for navigation metrics (Nav Cold TTR, Nav Warm TTR, Nav TTI)
eas observe:events Custom events emitted by the app via logEvent — name summary, all events, or filtered by event name (paginated)
eas observe:session Full timeline of metric and log events for one session
eas observe:versions App version hierarchy with build numbers, OTA update IDs, and event counts

Older published docs list only metrics-summary, metrics, events, and versions. All six are on the Querying with EAS CLI page; run --help to confirm them on your installed version.

All six commands share these flags:

  • --start <ISO date> and --end <ISO date> — explicit time range
  • --days <N> — show data from the last N days (mutually exclusive with --start/--end, minimum 1)
  • --project-id <id> — run against a specific project without needing a project directory. When passed, the command will not try to create a new EAS project where one is unneeded.
  • --json — machine-readable output (implies --non-interactive)
  • --non-interactive — fail instead of prompting

--platform ios / --platform android (default: both) is on every command except observe:session, which is scoped to one session already.

Default time range is the last 60 days when none of --days, --start, --end is given.

Plan gating. Observe is a paid feature, and the server rejects queries the account's plan does not include (EAS_OBSERVE_PLAN_UPGRADE_REQUIRED or EAS_OBSERVE_FEATURE_NOT_AVAILABLE_IN_FREE_TIER). The CLI surfaces the server's upgrade message, which links to the account's billing page. Session timelines in particular are checked before the interactive picker runs. A plan-gate failure is not a bug in the command or its flags.

Supported Metrics

App-startup metrics

Alias Full name Display
tti expo.app_startup.tti Startup TTI (time to interactive)
ttr expo.app_startup.ttr Startup TTR (time to render)
cold_launch expo.app_startup.cold_launch_time Cold Launch
warm_launch expo.app_startup.warm_launch_time Warm Launch
bundle_load expo.app_startup.bundle_load_time Bundle Load
update_download expo.updates.download_time Update Download

Navigation metrics

Emitted only when a navigation integration is enabled (SDK 56+). Measured per route name.

Alias Full name Display
nav_cold_ttr expo.navigation.cold_ttr Nav Cold TTR
nav_warm_ttr expo.navigation.warm_ttr Nav Warm TTR
nav_tti expo.navigation.tti Nav TTI

Which command takes which alias. observe:metrics (positional argument) and observe:metrics-summary --metric accept all nine aliases — startup and navigation. observe:routes --metric accepts only the three navigation aliases. Use the nav_ prefix everywhere; there are no bare cold_ttr / warm_ttr aliases.

observe:metrics also accepts a full metric name in place of an alias, for example eas observe:metrics expo.app_startup.tti. observe:routes accepts full navigation names the same way. The --metric flags on metrics-summary and routes are strict oclif options, so they take aliases only.

eas observe:metrics-summary

Shows per-version statistical aggregates for one or more metrics, with separate tables per platform.

# All default metrics, last 60 days, both platforms
eas observe:metrics-summary

# Single metric
eas observe:metrics-summary --metric tti

# Multiple metrics — each renders as its own table
eas observe:metrics-summary --metric tti --metric cold_launch

# Navigation metrics aggregate per version here, per route in observe:routes
eas observe:metrics-summary --metric nav_tti

# Choose which statistics to display
eas observe:metrics-summary --metric tti --stat median --stat p90 --stat eventCount

# Narrow time range and platform
eas observe:metrics-summary --metric tti --days 14 --platform ios

Stat flags: exactly min, median, max, average, p80, p90, p99, eventCount. This command takes no aliases — med, avg, and count are rejected here (they work only on observe:routes).

Default stats: median + eventCount in the table; all eight in JSON.

This command has no --limit, --after, --app-version, or --update-id. It always aggregates every version in the time range.

Table layout:

  • One table per metric (with merged value + event count cells, e.g. 0.45s (150))
  • Each table shows iOS and Android in separate sections
  • App Version column includes build numbers in parentheses (e.g. 1.2.0 (42))
  • Footer row per platform shows total events per metric
  • Update IDs are omitted from the table to keep output readable when a version has many updates; they are included in the JSON output as an array per version

JSON output shape:

{
  "versions": [
    {
      "appVersion": "1.2.0",
      "platform": "IOS",
      "buildNumbers": ["42"],
      "updateIds": ["abc-def-...", "..."],
      "metrics": {
        "expo.app_startup.tti": { "median": 0.45, "p90": 0.9, "...": "..." }
      }
    }
  ],
  "totalEventCounts": {
    "expo.app_startup.tti": { "IOS": 1234, "ANDROID": 890 }
  }
}

eas observe:metrics

Shows individual performance metric samples, paginated. The metric is a positional argument, not a flag. If omitted and running interactively, prompts for selection; in non-interactive mode it throws an error.

# Interactive: prompts for metric
eas observe:metrics

# Specify metric as positional arg
eas observe:metrics tti

# Navigation metrics work here too
eas observe:metrics nav_tti --sort slowest

# Filter by version or update, sort by slowest
eas observe:metrics tti --app-version 1.2.0 --sort slowest --limit 20

# Pagination — pass the endCursor from the previous run
eas observe:metrics tti --after <cursor>

Sample-specific flags:

  • --sort <oldest|newest|slowest|fastest> — defaults to oldest
  • --limit <N> — samples per page (default 10, max 100)
  • --after <cursor> — pagination cursor from the previous run
  • --app-version <version> — filter by app version string
  • --update-id <id> — filter by EAS update ID

Table layout:

  • Summary header shows the metric name, time range, and total sample count across all versions (e.g. TTI samples for the last 60 days — 1,234 total events)
  • Columns: Value, App Version (with build number), Update (only when any sample has one), Platform, Device, Country, Timestamp
  • When hasNextPage is true, prints Next page: --after <endCursor> hint below the table
  • JSON output also includes sessionId, easClientId, and a customParams object per sample

eas observe:routes

Shows per-route statistical aggregates for navigation metrics (Cold TTR, Warm TTR, Nav TTI), grouped by route name with separate sections per platform.

# All three navigation metrics, default stats, last 60 days, both platforms
eas observe:routes

# Single metric, last 7 days, iOS only
eas observe:routes --metric nav_tti --days 7 --platform ios

# Multiple metrics and stats
eas observe:routes --metric nav_cold_ttr --metric nav_warm_ttr --stat median --stat p90 --stat count

# Filter to a single build
eas observe:routes --app-version 1.2.0 --build-number 42

# Narrow to specific routes (repeat the flag for multiple routes)
eas observe:routes --route-name /new --route-name /settings

# Pagination — each platform has its own cursor; pass the relevant endCursor
eas observe:routes --after <cursor>

Routes-specific flags:

  • --metric <nav_cold_ttr|nav_warm_ttr|nav_tti> — navigation metric(s) to display, can be repeated. Defaults to all three.
  • --stat <median|p90|count> — statistic(s) per metric. Aliases: med → median, event_count / eventCount → count.
  • --limit <N> — routes per page (default 50, max 200, different from metrics/events which default to 10).
  • --after <cursor> — pagination cursor from the previous run.
  • --app-version <version> — filter by app version string.
  • --build-number <number> — filter by app build number (routes-only).
  • --route-name <name> — filter by route name. Repeatable; only the listed routes are returned across both platforms. Duplicates are de-duplicated; omitting the flag returns all routes.
  • --update-id <id> — filter by EAS update ID.

Default stats: median + count in the table; median, p90, count in JSON.

Table layout:

  • Summary header with the chosen stats and time range, e.g. Med, P90 values (navigation count) for the last 7 days.
  • Separate iOS and Android sections.
  • First column is Route, followed by one column per metric/stat. With both display stats and count, cells are merged like 0.32s (1240).
  • Each platform has its own pagination hint: Next page (iOS): --after <endCursor>.

JSON output shape:

{
  "routes": [
    {
      "routeName": "(tabs)/home",
      "platform": "IOS",
      "metrics": {
        "expo.navigation.cold_ttr": { "median": 0.32, "p90": 0.85, "count": 1240 },
        "expo.navigation.tti":       { "median": 0.55, "p90": 1.10, "count": 1240 }
      }
    }
  ],
  "pageInfoByPlatform": {
    "IOS":     { "hasNextPage": true,  "endCursor": "..." },
    "ANDROID": { "hasNextPage": false, "endCursor": null }
  }
}

eas observe:events

Shows custom events emitted by the app via the logEvent API in expo-observe. Behavior depends on what is passed:

Invocation Result
observe:events Summary table of available event names with counts
observe:events --all-events Full list of events across all event names
observe:events <event-name> Full list of events filtered by that event name
# List the available custom event names and their counts (last 60 days)
eas observe:events

# All events across all names, last 7 days, iOS only
eas observe:events --all-events --days 7 --platform ios

# Only events with the given name
eas observe:events login_failed --limit 50

# Drill into a single session
eas observe:events --all-events --session-id <session-id>

# Pagination
eas observe:events login_failed --after <cursor>

Events-specific flags:

  • --all-events — when no event name argument is given, list all events instead of the name summary. Cannot be combined with an event name argument.
  • --session-id <id> — filter to events from a single session (events-only). With no event name argument, this lists the session's events instead of the event-name summary. For the full timeline — metrics as well as log events — use observe:session.
  • --app-version <version> — filter by app version string
  • --update-id <id> — filter by EAS update ID
  • --limit <N> — events per page (default 10, max 100)
  • --after <cursor> — pagination cursor

Table layout (event listings):

  • Summary header: <event-name> events <time range> or Custom events <time range> for --all-events, with a total event count when available
  • Columns: Timestamp, Event (only when listing across multiple names), Severity (only when at least one event in the page has a severity), App Version (with build number), Platform, Device, Country
  • Next page: --after <endCursor> hint below the table when there is a next page

Empty-result helper: if a specific event name is queried and returns no events, the command prints a yellow No events found matching "<name>" warning followed by the available event names + counts in the same time range — useful for fixing typos.

Truncation note: the event-names summary may flag Result is truncated; not all event names are shown. when there are more names than the server returns in a single response.

JSON output shape (event listing):

{
  "events": [
    {
      "id": "...",
      "eventName": "login_failed",
      "timestamp": "2026-...",
      "sessionId": "...",
      "severityNumber": 13,
      "severityText": "WARN",
      "properties": [{ "key": "reason", "value": "bad_password", "type": "string" }],
      "appVersion": "1.2.0",
      "appBuildNumber": "42",
      "appUpdateId": null,
      "appEasBuildId": null,
      "deviceModel": "...",
      "deviceOs": "iOS",
      "deviceOsVersion": "17.4",
      "countryCode": "US",
      "environment": "production",
      "easClientId": "..."
    }
  ],
  "pageInfo": { "hasNextPage": true, "endCursor": "..." }
}

The name-summary mode returns { "names": [{ "eventName": "...", "count": 123 }], "isTruncated": false }.

eas observe:session

Shows the full timeline of metric and log events for a single session — the CLI equivalent of the dashboard's session view. Use it after observe:metrics surfaces a slow sample: take that sample's sessionId (present in --json output) and replay everything that session recorded.

# Interactive: pick a metric, then pick a session from the candidate list
eas observe:session

# Inspect a known session
eas observe:session <session-id>

# Pick a session from the slowest TTI events in the last 7 days
eas observe:session --event-name tti --sort slowest --days 7

Session-specific flags:

  • [SESSIONID] — positional. Omit it in interactive mode to choose from a list. Required in non-interactive mode, including under --json.
  • --event-name <name> — metric or log event used to build the candidate session list (for example tti, cold_launch, login_pressed). Prompts when omitted in interactive mode.
  • --sort <slowest|fastest|newest|oldest> — orders the candidate events. Prompts when omitted in interactive mode. No default, unlike observe:metrics.

The picker flags and the session ID are mutually exclusive. --event-name, --sort, --days, --start, and --end describe how to find a session, so passing any of them together with a session ID throws. Query a known session with the ID alone.

This command has no --platform, --limit, or --after flag. It takes the shared time-range, --project-id, --json, and --non-interactive flags.

JSON output shape:

{
  "sessionId": "...",
  "metadata": { "...": "..." },
  "entries": [{ "...": "..." }],
  "hasMoreMetricEvents": false,
  "hasMoreLogEvents": false
}

entries interleaves metric and log events for the session. The two hasMore* flags report truncation per event kind; there is no cursor to page with.

eas observe:versions

Shows app version hierarchy with build numbers, OTA update IDs, and event counts per version.

# Both platforms, last 60 days
eas observe:versions

# iOS only, last 14 days
eas observe:versions --days 14 --platform ios

No metric-related flags. Output shows separate iOS and Android tables with columns: App Version, First Seen, Events, Users, Builds (count), Updates (count).

JSON output returns the full nested hierarchy with buildNumbers[].easBuilds[] and updates[].easBuilds[], including firstSeenAt, eventCount, and uniqueUserCount at every level.

Common Workflows

"What are my app's startup times right now?"

eas observe:metrics-summary --days 7 --stat median --stat p90

"Which TTI samples were slowest this week?"

eas observe:metrics tti --sort slowest --days 7 --limit 20

"How fast are over-the-air updates downloading in the field?"

eas observe:metrics-summary --metric update_download --days 7

"Which screens are slowest to navigate to?"

eas observe:routes --metric nav_tti --stat median --stat p90 --days 7

"What happened during that one slow session?"

eas observe:metrics tti --sort slowest --days 7 --json   # read sessionId from a sample
eas observe:session <session-id>

"How does navigation perform on just the routes I care about?"

eas observe:routes --route-name /home --route-name /checkout --days 7

"What custom events is my app emitting?"

eas observe:events --days 7

"Show me every error event from one user's session."

eas observe:events --all-events --session-id <session-id>

"What versions of my app are in the field?"

eas observe:versions

"Show me metrics for a specific project without needing to be in the repo"

eas observe:metrics-summary --project-id <uuid> --metric tti

"Get JSON for scripting"

eas observe:metrics-summary --metric tti --json --non-interactive

Notes

  • Requires the user to be logged in (eas login).
  • When --project-id is provided, the command does not require running inside an EAS project directory; otherwise the project ID is read from the local app.config / app.json. If using this option, ensure that you are logged in as a user that has access to the specified project.
  • observe:metrics-summary does not print update IDs in the table but still returns them in JSON for scripting or piping into other commands.

Source: SKILL.md on GitHub

No alerts1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    The skill provides comprehensive documentation and implementation guides for EAS Observe, a performance monitoring service for Expo applications. All instructions and tools described are standard components of the Expo development ecosystem.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at 948115e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 2 months ago
version
1.1.0

README badge

README badge for expo/skills/eas-observe