-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Description
Overview
We need a new end-to-end performance metric that measures the time from when the user taps the Create Expense button (the submit/confirm action on the confirmation step) until the destination page is fully rendered and visible to the user.
This metric should cover all expense types and all possible navigation destinations after expense creation.
Why this matters
After a user confirms an expense, they experience a transition period: the confirmation modal dismisses, navigation occurs, and a destination page renders. This is a critical moment in the user experience — the user is waiting to see the result of their action. Any delay here feels like lag or broken behavior. We currently lack visibility into this end-to-end duration across all creation flows.
Current telemetry coverage
We already have several spans measuring parts of the expense creation flow:
| Span | What it measures | Gap |
|---|---|---|
ManualOpenCreateExpense |
Opening the creation UI (from startMoneyRequest() to confirmation page layout) |
None — this is a separate flow |
ManualShutterToConfirmation |
Camera shutter press to confirmation screen layout (scan only) | None — this is a separate flow |
ManualCreateExpenseSubmit |
Submit button click to API dispatch completion | Ends at API dispatch, not at destination render |
ManualCreateExpenseNavigation |
Post-submit navigation to destination | Only covers the Search page destination — all other destinations are unmeasured |
The ManualCreateExpenseNavigation span currently only ends when the Search list component lays out (markNavigateAfterExpenseCreateEnd() in src/components/Search/index.tsx). This means we have no measurement for the majority of post-creation navigation scenarios.
What to measure
Start point: The moment the user taps the Create/Submit/Confirm button on the expense confirmation step (in IOURequestStepConfirmation.tsx).
End point: The moment the destination page is fully rendered and visible to the user (e.g., onLayout of the main content list/view on the destination screen).
Duration: The entire end-to-end time including optimistic data application, modal dismissal animation, navigation, and destination page render.
Expense types to cover
All expense creation request types:
- Manual expense
- Scan (receipt) expense
- Distance expense (manual, GPS, odometer variants)
- Per diem expense
- Time expense
All IOU types:
- Submit (request money from someone)
- Track (track expense for self)
- Split (split bill among participants)
- Invoice (send invoice)
- Pay / Send money
Navigation destinations to cover
After creating an expense, the user can land on many different pages depending on the context (which tab they were on, whether they used global create, whether a report was already open, etc.). All of these destinations need to be measured:
- Report chat (Inbox tab) — the most common path; the user is taken to the chat report containing the expense (via
dismissModalWithReport) - Search expenses/reports page — when creating from global create while not on the Inbox tab, the user lands on the Search page with the expense type filter (via
Navigation.navigate(ROUTES.SEARCH_ROOT)) - Money request report in Search RHP — when adding an expense to a report that already has multiple transactions and is open in the wide RHP (via
Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT)) - RHP pop/dismiss — when a report is already open in the RHP and the user adds an expense to it, the RHP is popped or dismissed to show the updated report (via
Navigation.pop()ordismissToPreviousRHP()) - Modal dismiss only — when search is the topmost route or there is no reportID, the modal is simply dismissed (via
Navigation.dismissModal()) - Split bill chat report — after splitting a bill, the user lands on the split chat report
- Invoice report — after sending an invoice
- Self DM — for per diem expenses submitted to self
Useful attributes / dimensions
To segment and analyze the metric effectively, the span(s) should capture attributes such as:
- Expense type (manual, scan, distance, per diem, time)
- IOU type (submit, track, split, invoice, pay)
- Destination type (report chat, search page, RHP, modal dismiss, etc.)
- Whether created from global create vs. from within an existing report
- Whether a receipt is attached
- Platform (iOS, Android, web — available via Sentry device context)
- Whether the destination was already mounted (warm) vs. freshly navigated to (cold)
Related code
src/pages/iou/request/step/IOURequestStepConfirmation.tsx— confirmation step where submit is triggeredsrc/libs/actions/IOU/index.ts—handleNavigateAfterExpenseCreate(),dismissModalAndOpenReportInInboxTab(), and all creation functions (requestMoney,trackExpense,createDistanceRequest,submitPerDiemExpense, etc.)src/libs/actions/IOU/Split.ts—splitBill,splitBillAndOpenReport,startSplitBillsrc/libs/actions/IOU/SendInvoice.ts—sendInvoicesrc/libs/actions/IOU/SendMoney.ts—sendMoneyElsewhere,sendMoneyWithWalletsrc/libs/telemetry/activeSpans.ts— span management utilitiessrc/libs/telemetry/markSubmitExpenseEnd.ts— existing submit span end markersrc/libs/telemetry/markNavigateAfterExpenseCreateEnd.ts— existing navigation span end marker (Search page only)src/components/Search/index.tsx— where the current navigation end marker firessrc/CONST/index.ts— telemetry span constants (lines ~1786-1791)
Metadata
Metadata
Assignees
Type
Projects
Status