Skip to content

📈 - Add EAS Observe for startup performance metrics#636

Merged
guytepper merged 1 commit into
mainfrom
add-eas-observe
Jun 28, 2026
Merged

📈 - Add EAS Observe for startup performance metrics#636
guytepper merged 1 commit into
mainfrom
add-eas-observe

Conversation

@guytepper

Copy link
Copy Markdown
Member

Summary

Adds EAS Observe to track app-startup performance (cold/warm launch, TTR, TTI) from production builds.

Changes

  • Install expo-observe@~56.0.21 (SDK 56-compatible).
  • Wrap the root layout export with ObserveRoot.wrap(...) (composed with the existing Sentry.wrap) — measures Time to First Render automatically.
  • Call markInteractive() via the useObserve() hook once storeReady && localeReady — i.e. exactly when the app stops rendering null and shows real UI — to record Time to Interactive.
  • Bump app version to 2.7.1.

Notes

  • Metrics only dispatch from real release builds (debug/dev builds are ignored by default), so data appears after the next eas build, under the Observe tab in the EAS dashboard.
  • markInteractive() is placed in the root ready-gate, covering normal launches. Deep-link launches into a modal/screen aren't separately tracked yet — the optional per-route Expo Router integration could be added later if we want per-screen TTI.

https://claude.ai/code/session_01HGgWseHtmPxgmsJuhXyWB5

Install expo-observe and wire it into the root layout: wrap with
ObserveRoot for Time to First Render, and call markInteractive() once
the store and locale are ready for Time to Interactive. Also bump app
version to 2.7.1.

Claude-Session: https://claude.ai/code/session_01HGgWseHtmPxgmsJuhXyWB5
@guytepper guytepper merged commit 83d745d into main Jun 28, 2026
1 check passed
@guytepper guytepper deleted the add-eas-observe branch June 28, 2026 21:21

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates expo-observe into the application to track when the app becomes interactive, wrapping the root layout with ObserveRoot and bumping the app version to 2.7.1. The feedback suggests using a useRef to guarantee that markInteractive() is called exactly once when the store and locale are ready, preventing potential duplicate signals.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread app/_layout.tsx
const [localeReady, setLocaleReady] = useState(false)
const appState = useRef(AppState.currentState)
const router = useRouter()
const { markInteractive } = useObserve()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential duplicate calls to markInteractive() (for instance, if the markInteractive function returned by useObserve() is not stable across renders, or if other dependencies change), it is safer to use a useRef to guarantee that the interactive signal is sent exactly once.

Suggested change
const { markInteractive } = useObserve()
const { markInteractive } = useObserve()
const hasMarkedInteractive = useRef(false)

Comment thread app/_layout.tsx
Comment on lines +203 to +209
useEffect(() => {
// Signal EAS Observe that the app is interactive once the store + locale are
// ready — this is the point we stop returning null and render the real UI.
if (storeReady && localeReady) {
markInteractive()
}
}, [storeReady, localeReady, markInteractive])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the hasMarkedInteractive ref to ensure markInteractive() is only invoked once when both the store and locale become ready.

Suggested change
useEffect(() => {
// Signal EAS Observe that the app is interactive once the store + locale are
// ready — this is the point we stop returning null and render the real UI.
if (storeReady && localeReady) {
markInteractive()
}
}, [storeReady, localeReady, markInteractive])
useEffect(() => {
// Signal EAS Observe that the app is interactive once the store + locale are
// ready — this is the point we stop returning null and render the real UI.
if (storeReady && localeReady && !hasMarkedInteractive.current) {
hasMarkedInteractive.current = true
markInteractive()
}
}, [storeReady, localeReady, markInteractive])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant