Context
Follow-up to RN-541, which introduces the standalone app.start transaction with the Span V2 attributes app.vitals.start.value and app.vitals.start.type. #5839 deliberately left one open question unresolved:
Open question: emit app.vitals.start.screen directly, or rely on Relay's backfill from the transaction name?
This issue tracks resolving that question for React Native.
Decision: emit it directly
Relay's app.vitals.start.screen backfill (relay-event-normalization) derives the screen from the transaction name, and was designed for V1, where app start rode on the screen-named ui.load transaction. Our standalone transaction is named App Start, so the name-based backfill produces a meaningless value — the SDK must set the attribute itself.
The sibling mobile SDKs already do this on their standalone transactions:
- Android (
ActivityLifecycleIntegration.java): sets app.vitals.start.screen to the first Activity's name (APP_START_SCREEN_DATA = "app.vitals.start.screen"; test asserts "Activity"). Also sets app.vitals.start.reason on API 35+.
- Cocoa: dedicated
SentrySpanDataKeyAppVitalsStartScreen = "app.vitals.start.screen", documented as "Used by standalone app start transactions to set the app.vitals.start.screen attribute."
So the cross-SDK target is clear: emit app.vitals.start.screen directly on the app.start transaction.
RN-specific complication
Android/Cocoa know the first Activity/screen at app-start completion. The RN equivalent is the first React Navigation route name (already tracked via SEMANTIC_ATTRIBUTE_ROUTE_NAME). The difficulty:
- The standalone transaction is captured at root-component mount (deferred via
setTimeout(0) in captureStandaloneAppStart), which can fire before the first navigation route is registered. At that moment the screen may be unknown.
Possible approaches to evaluate:
- Read the first route from the navigation integration if it is already available at capture time; skip the attribute when it is not.
- Briefly defer / lazily populate the screen once the first route is known (coordinate with the deferred-send /
appLoaded flow already used in standalone mode).
- For Expo Router, source the screen from the router state.
Scope
- JS only.
- Set
app.vitals.start.screen on the standalone app.start transaction when the first screen/route is resolvable.
- Gracefully omit when it isn't (don't block sending the transaction —
value/type are the load-bearing attributes).
- Tests covering: screen present, screen absent (capture before route registration).
Out of scope
Context
Follow-up to RN-541, which introduces the standalone
app.starttransaction with the Span V2 attributesapp.vitals.start.valueandapp.vitals.start.type. #5839 deliberately left one open question unresolved:This issue tracks resolving that question for React Native.
Decision: emit it directly
Relay's
app.vitals.start.screenbackfill (relay-event-normalization) derives the screen from the transaction name, and was designed for V1, where app start rode on the screen-namedui.loadtransaction. Our standalone transaction is namedApp Start, so the name-based backfill produces a meaningless value — the SDK must set the attribute itself.The sibling mobile SDKs already do this on their standalone transactions:
ActivityLifecycleIntegration.java): setsapp.vitals.start.screento the first Activity's name (APP_START_SCREEN_DATA = "app.vitals.start.screen"; test asserts"Activity"). Also setsapp.vitals.start.reasonon API 35+.SentrySpanDataKeyAppVitalsStartScreen = "app.vitals.start.screen", documented as "Used by standalone app start transactions to set theapp.vitals.start.screenattribute."So the cross-SDK target is clear: emit
app.vitals.start.screendirectly on theapp.starttransaction.RN-specific complication
Android/Cocoa know the first Activity/screen at app-start completion. The RN equivalent is the first React Navigation route name (already tracked via
SEMANTIC_ATTRIBUTE_ROUTE_NAME). The difficulty:setTimeout(0)incaptureStandaloneAppStart), which can fire before the first navigation route is registered. At that moment the screen may be unknown.Possible approaches to evaluate:
appLoadedflow already used in standalone mode).Scope
app.vitals.start.screenon the standaloneapp.starttransaction when the first screen/route is resolvable.value/typeare the load-bearing attributes).Out of scope
app.vitals.start.reason(OS launch reason) — Android-specific (ApplicationStartInfo); no RN equivalent.value/type(handled in feat(tracing): Decouple app start data from navigation transaction lifecycle #5839).