eas-update-insights

作者: expo

檢查已發布的 EAS 更新的健康狀況:崩潰率、安裝/啟動次數、唯一用戶數、有效載荷大小,以及每個…的嵌入式與 OTA 用戶分佈。

npx skills add https://github.com/expo/skills --skill eas-update-insights

EAS Update Insights

Query the health of published EAS Updates directly from the CLI: launches, failed launches, crash rates, unique users, payload size, the embedded-vs-OTA user split per channel, and the most popular updates per runtime version. The data is the same data that powers the update and channel detail pages on expo.dev; these commands expose it in the terminal in human and JSON form.

When to use this skill

Use this when the user wants to assess the health or adoption of a published EAS Update: crash rates, install counts, unique users, bundle size, or the split between embedded and OTA users on a channel.

Example prompts:

  • "How is the latest update doing?"
  • "Is the latest update healthy?"
  • "Is the new release crashing more than the last one?"
  • "How many users are on the latest update vs the embedded build?"
  • "Which update is most popular on production right now?"
  • "How big is our update bundle?"

Also fits: post-publish rollout monitoring and regression detection.

Don't use when the user needs per-user crash detail or device-level reporting; this skill only exposes aggregate EAS metrics.

Prerequisites

  • eas-cli installed (npm install -g eas-cli).
  • Logged in: eas login.
  • For channel:insights: run from an Expo project directory (the command resolves the project ID from app.json). update:insights only needs a login.

Commands at a glance

CommandPurpose
eas update:listDiscover recent update groups, their group IDs, and branch names
eas update:insights <groupId>Per-platform launches, failed launches, crash rate, unique users, payload size, daily breakdown
eas update:view <groupId> --insightsUpdate group details + the same metrics appended
eas channel:insights --channel <name> --runtime-version <version>Embedded/OTA user counts, most popular updates, cumulative metrics for a channel + runtime

All of these support --json --non-interactive for programmatic parsing.

Discovering IDs

Before querying insights for an update group, you need its group ID. Use eas update:list with either --branch <name> (updates on that branch) or --all (updates across all branches). Always pass --json --non-interactive when running non-interactively; without a branch/--all flag the command will otherwise prompt for a branch selection:

# Latest group id across all branches
eas update:list --all --json --non-interactive | jq -r '.currentPage[0].group'

# Latest group id on a specific branch
eas update:list --branch production --json --non-interactive | jq -r '.currentPage[0].group'

The JSON response has a currentPage array with one entry per update group (both platforms of the same publish are collapsed into one entry):

{
  "currentPage": [
    {
      "branch": "production",
      "message": "\"Fix checkout crash\" (1 week ago by someone)",
      "runtimeVersion": "1.0.6",
      "group": "03d5dfcf-736c-475a-8730-af039c3f4d06",
      "platforms": "android, ios",
      "isRollBackToEmbedded": false
    }
  ]
}

Entries also carry codeSigningKey and rolloutPercentage, but only when those features are in use for the group (undefined values are omitted from the JSON output).

When called with --branch <name>, the response also includes name (the branch name) and id (the branch ID) at the top level.

eas update:insights <groupId>

Shows launches, failed launches, crash rate, unique users, launch asset count, and average payload size for a single update group, broken down per platform (iOS, Android), plus a daily breakdown of launches and failures.

Basic use

eas update:insights 03d5dfcf-736c-475a-8730-af039c3f4d06

Flags

FlagDescription
--days <N>Look back N days. Default: 7. Mutually exclusive with --start/--end.
--start <iso-date> / --end <iso-date>Explicit time range, e.g. --start 2026-04-01 --end 2026-04-15.
--platform <ios|android>Filter to a single platform. Omit to see all platforms in the group.
--jsonMachine-readable output. Implies --non-interactive.
--non-interactiveRequired when scripting.

JSON output shape

Top level: groupId, timespan (start, end, daysBack), and platforms[] with one entry per platform the group was published to. Each platform entry has updateId, totals (uniqueUsers, installs, failedInstalls, crashRatePercent), payload (launchAssetCount, averageUpdatePayloadBytes), and a daily[] time series of { date, installs, failedInstalls }.

For the complete schema and field reference, see references/update-insights-schema.md.

Fields that matter for health assessment:

  • platforms[].totals.crashRatePercent, computed as failedInstalls / (installs + failedInstalls) * 100. Zero when there are no installs.
  • platforms[].totals.installs and uniqueUsers give the adoption signal.
  • platforms[].daily is a time series, useful for spotting a sudden spike in failures.

Errors

  • Could not find any updates with group ID: "<id>" — group doesn't exist or you lack access.
  • Update group "<id>" has no ios update (available platforms: android)--platform ios was used but the group wasn't published for iOS.
  • EAS Update insights is not supported by this version of eas-cli. Please upgrade ... — the server deprecated a field the CLI relies on. Run npm install -g eas-cli@latest.

eas update:view <groupId> --insights

Extends the standard update:view output with the same per-platform insights, inline.

# Human-readable
eas update:view 03d5dfcf-... --insights
eas update:view 03d5dfcf-... --insights --days 30

# JSON: wrapped as { updates: [...], insights: {...} }
eas update:view 03d5dfcf-... --json --insights

Without --insights, update:view behaves exactly as before — no JSON shape change for existing consumers. The --days / --start / --end flags only apply when --insights is set; passing them alone errors.

eas channel:insights --channel <name> --runtime-version <version>

Shows, per channel, how many users are on the embedded build vs over-the-air updates and which updates are pulling the most traffic. Must be run from an Expo project directory.

Basic use

eas channel:insights --channel production --runtime-version 1.0.6

Flags

FlagDescription
--channel <name>Required. The channel name (e.g. production, staging).
--runtime-version <version>Required. Match exactly what was published. Check runtimeVersion values in update:list.
--days <N>Look back N days. Default: 7.
--start / --endExplicit time range, like update:insights.
--json / --non-interactiveMachine-readable output.

JSON output shape

Top level: channel, runtimeVersion, timespan, embeddedUpdateTotalUniqueUsers, otaTotalUniqueUsers, mostPopularUpdates[] (each with rank, groupId, message, platform, totalUniqueUsers), cumulativeMetricsAtLastTimestamp[], plus chart-shaped uniqueUsersOverTime and cumulativeMetricsOverTime objects with labels and datasets.

For the complete schema and field reference, see references/channel-insights-schema.md.

Fields that matter:

  • embeddedUpdateTotalUniqueUsers is the count of users running the embedded (binary-bundled) build.
  • mostPopularUpdates[] is updates ranked by totalUniqueUsers. Caveat: this is the top-N the server returns; otaTotalUniqueUsers is a sum of that list and may undercount total OTA reach if more than top-N updates are active.
  • uniqueUsersOverTime and cumulativeMetricsOverTime are daily data series for charting.

Errors

  • Could not find channel with the name <name> — typo or wrong account.
  • "No update launches recorded" in the table / empty mostPopularUpdates in JSON — no OTA update has been launched for that channel + runtime yet. Usually means the channel is still serving the embedded build only.

Common workflows

Verify the update I just published is healthy

# 1. Grab the latest publish on production
GROUP_ID=$(eas update:list --branch production --json --non-interactive \
  | jq -r '.currentPage[0].group')

# 2. Give it some adoption time (minutes to hours), then check crash rate
eas update:insights "$GROUP_ID" --json --non-interactive \
  | jq '.platforms[] | {platform, installs: .totals.installs, crashRate: .totals.crashRatePercent}'

Compare the crashRate across platforms and against previous releases; sudden spikes or asymmetric behaviour (iOS spiking while Android is flat, or vice versa) is the signal to investigate.

Compare adoption between two channels

for channel in production staging; do
  echo "--- $channel ---"
  eas channel:insights --channel "$channel" --runtime-version 1.0.6 --json --non-interactive \
    | jq '{
        channel,
        embedded: .embeddedUpdateTotalUniqueUsers,
        ota: .otaTotalUniqueUsers,
        topUpdate: .mostPopularUpdates[0]
      }'
done

Detect a rollout regression in the last 24 hours

eas update:insights "$GROUP_ID" --days 1 --json --non-interactive \
  | jq '.platforms[] | select(.totals.crashRatePercent > 1)'

Summarize group metrics for release notes

eas update:view "$GROUP_ID" --insights --days 30

Human-readable group details plus 30 days of launches/failures per platform — suitable for pasting into a changelog or incident review.

Output tips

  • Pipe JSON through jq; payloads are structured for easy filtering.
  • --json implies --non-interactive, but passing both is explicit and scripting-friendly.
  • Dates in daily[].date are UTC ISO timestamps; the human-readable table renders them as YYYY-MM-DD (UTC).
  • The CLI table labels say "Launches" / "Crashes" while JSON uses installs / failedInstalls. Same field, different display name.

Limitations

  • Unique users across platforms may double-count users who run the same publish on both iOS and Android. The same caveat applies to otaTotalUniqueUsers in channel insights, which is a sum over mostPopularUpdates.
  • Fresh publishes may show zeros for a short period while the metrics pipeline catches up.
  • Installs are downloads, not launches: the installs / "Launches" field counts users who downloaded the manifest and launch asset. A confirmed run only registers on the user's next update check (typically up to 24h later, depending on the app's update policy). So metrics lag the real-world state slightly.
  • Crashes are self-reported: failedInstalls / "Crashes" counts updates that errored during install/launch and were reported on the next update check. Crashes that don't trigger an update request (e.g. process kill before recovery) won't appear.

來自 expo 的更多技能

android-e2e-testing
expo
使用 ADB 在 Android 模擬器上測試 Expo Router 功能。在實作原生 Android 功能後或驗證 Android 上的 UI 行為時使用。
official
deep-code-review
expo
深度設計導向的程式碼審查——在評估 PR 變更前先理解程式碼庫背景,並將結構化回饋發布至 GitHub
official
building-native-ui
expo
使用路由、樣式、元件及平台慣例建構原生 Expo 應用程式的完整指南。涵蓋 Expo Router 基礎、原生分頁、堆疊導航、模態視窗與表單頁面,並詳述路由結構慣例。包含符合 Apple 人機介面指南的樣式規則:flexbox 佈局、安全區域處理、動畫、透過 CSS boxShadow 實現的陰影效果,以及響應式設計模式。記錄函式庫偏好設定(expo-image 用於 SF Symbols、expo-audio、expo-video……)
official
expo-api-routes
expo
在 Expo Router 中使用 API 路由處理伺服器端邏輯、機密資料及第三方整合,適用於 EAS Hosting。在 app 目錄中建立以 +api.ts 結尾的路由;匯出名稱對應的 HTTP 方法函式(GET、POST、PUT、DELETE)。處理查詢參數、標頭、JSON 主體及動態路由區段;為網頁客戶端加入 CORS 標頭。透過 process.env 存取伺服器端機密;在本地 .env 中設定變數,或透過 eas env:create 為正式環境設定。使用 eas 部署至 EAS Hosting(Cloudflare Workers)。
official
expo-cicd-workflows
expo
為Expo專案撰寫並驗證EAS CI/CD工作流程的YAML檔案。從Expo API獲取最新JSON結構,確保作業類型、參數、觸發條件及執行器配置皆為最新。支援使用${{ }}語法的動態表達式,可搭配GitHub事件、工作流程輸入、作業輸出及步驟結果等上下文。內建驗證腳本,能根據結構檢查工作流程並在部署前回報錯誤。提供語法參考文件...
official
expo-deployment
expo
自動化將 Expo 應用程式部署至 iOS App Store、Android Play Store、網頁主機及預覽環境。支援透過單一指令進行 iOS(App Store 與 TestFlight)及 Android(Google Play Store)的正式版本建置與提交。包含 EAS Hosting 網頁部署功能,可自動產生 PR 預覽網址並支援正式網域。透過 EAS Workflows 提供 CI/CD 工作流程自動化,在程式碼推送時觸發建置與提交。自動版本管理,支援遠端...
official
expo-dev-client
expo
透過 EAS Build 或在本機端建立自訂 Expo 開發用戶端,以便在實體裝置上測試原生程式碼。僅在使用自訂原生模組、Apple 目標(小工具、App Clips)或 Expo Go 中未包含的第三方原生程式碼時才需要;請先嘗試使用 npx expo start 執行 Expo Go。支援雲端建置並自動提交至 TestFlight,或在本機端建置,輸出 .ipa(iOS)或 .apk / .aab(Android)檔案。需要在 eas.json 中設定包含開發設定檔的組態,該設定檔會設定...
official
expo-module
expo
使用 Expo Modules API(Swift、Kotlin、TypeScript)建立與撰寫 Expo 原生模組與檢視的指南。涵蓋模組定義 DSL、原生…
official