Skip to content

[Metrics] ManualShutterToConfirmation - Optimize "Confirm details" page rendering after receipt capture #83503

Open
12 of 15 issues completed

Description

@Julesssss

Target: 400 miliseconds


Problem

After capturing a receipt photo, the transition to the "Confirm details" page adds noticeable latency. Even after improving the image capture pipeline itself, the rendering cost of the confirmation page may still be a bottleneck.

Goal

Profile the "Confirm details" page mount and render cycle to identify optimization opportunities. Reducing render time here would make the shutter-button-to-confirmation transition feel snappier.

Plan:

  • Add sentry tracking spans for the flow
  • @Julesssss to build sentry dashboard
  • Deep investigation into problematic areas and anywhere we can reduce rendering time and improve app performence on web and mobile platforms

Related

Activity

  1. self-assigned this
    on Feb 25, 2026
  2. marcaaron commented on Feb 26, 2026

    @marcaaron
    Contributor

    Not sure if there is enough data for the manual shutter span, but here's the query filtered to native since that's the only place that it matters. Some of those look kind of wonky so some spans might not be getting canceled.

  3. kubabutkiewicz commented on Feb 26, 2026

    @kubabutkiewicz
    Contributor

    Hi Jakub from Callstack, I would like to work on this issue.

  4. kubabutkiewicz commented on Feb 26, 2026

    @kubabutkiewicz
    Contributor

    Daily update:
    I was looking into this today so I can familiarise myself with the code and I am looking where we should add the spans and if we need only one span or more granular spans to be able to track all the parts of this flow.

  5. 186 remaining items

  6. cristipaval commented on Sep 17, 2026

    @cristipaval
    Contributor

    Thanks @OlimpiaZurek! Subissues ^

  7. OlimpiaZurek commented on Sep 22, 2026

    @OlimpiaZurek
    Contributor

    Update:

    I've been digging into the regression from the Slack thread, and it looks like the root cause is a telemetry bug rather than an Android slowdown. Since the recent Sentry SDK upgrade our spans are being cancelled and then dropped by the board's status:ok filter, which is why the sample collapsed so dramatically. 84% of shutter captures never reach the board. I'm working on a fix.

  8. OlimpiaZurek commented on Sep 23, 2026

    @OlimpiaZurek
    Contributor

    Update:

    PR with the fix is open for review: #101877

  9. cristipaval commented on Sep 23, 2026

    @cristipaval
    Contributor

    Thanks @OlimpiaZurek! I created an issue for it

  10. OlimpiaZurek commented on Oct 6, 2026

    @OlimpiaZurek
    Contributor

    Update:

    • Looked into why Android is so much slower on this flow. Most of the gap comes from two phases:
      • ManualConfirmationMount: even on high-end Android it takes ~1.9x as long as iOS (77 vs 44ms p50). Other flows on the same devices are only ~1.3-1.5x slower on Android (ManualOpenReport 1.41x, ManualNavigateToReports 1.44x, ManualOpenCreateExpense 1.29x), so mount looks like an outlier. There's no Android-specific code in the confirmation screen, so my guess is it's how Android renders it: creating native views and measuring text for all the footer fields can be expensive on the new architecture. Mount is mostly pure CPU work though, so part of it may just be slower phones. I can't tell how much from Sentry alone.
      • ManualReceiptCapture: Android snapshots are smaller than iOS (~1190×1584 vs 1440×1920) but take ~1.8x longer (97 vs 55ms p50). So it's not the image size, it's probably how VisionCamera takes snapshots on Android (copies the preview off the GPU, then compresses to JPEG). The full-photo path (flash/landscape, ~3% of Android captures) takes ~1.6s on Android vs ~0.6s on iOS and drives the slow tail.
    • perf: index 1:1 chats by participants instead of scanning reports on confirmation mount #101219 cuts work on confirmation mount on both platforms, and Android should benefit more from it. It's in 9.5.2 together with the telemetry fix ([NOQA] fix: start telemetry spans with no parent #101877), so we should see the real numbers in a few days.
    • Next step is to profile the confirmation mount on a real Android device to confirm where the time goes, and check whether the VisionCamera v5 snapshot is any faster.
  11. Julesssss commented on Oct 8, 2026

    @Julesssss
    ContributorAuthor

    Reworked quality PR merged, we'll keep an eye on both timing and image quality.

  12. OlimpiaZurek commented on Oct 14, 2026

    @OlimpiaZurek
    Contributor

    Update:

    Checked the regression flagged in the latest Slack thread, and it looks like it’s not a real regression.

    • The 602 -> 791 jump probably comes from the telemetry fix Expensify/App#101877 . Before it, the board only picked up the fast captures. Since then, Android p95 mostly depends on how many flash shots land in each release, and mount p95 has stayed around 285-320ms.
    • Flash on Android more than doubled from September to October (~2.3% → ~5.2% of captures). At ~1.7s per shot, that’s enough to set Android p95. Could be seasonal, a UI change or a different mix of users, so I think it’s worth checking.
    • The one PR I’d keep an eye on is my own Expensify/App#100592 . It processes the full photo in the background, which on Android can overlap with the confirmation screen loading. Early 9.5.7 data is going the wrong way (mount p95 292 → 516ms), but it’s only ~180 samples. I’ll check again next week.

    Other options to make Android faster:

    • Flash: the v5 upgrade (Expensify/App#102898) already sets qualityPrioritization, so I’ll check flash and Android p95 once it’s merged.
    • Snapshot: on v4, Android takes the snapshot on the UI thread. I’ll check whether v5 does the same, and if so, whether moving the JPEG encoding off the UI thread could be a proper fix
  13. OlimpiaZurek commented on Oct 15, 2026

    @OlimpiaZurek
    Contributor

    Update:
    Tried a few Android-specific ideas:

    • Closing the camera while the confirmation page mounts: no difference. Mount took the same time whether the camera stayed on or not, and with both takeSnapshot and takePhoto.
    • Moving the snapshot JPEG encoding off the UI thread (a patch on VisionCamera v4): no gain. Capture got ~15ms slower and mount ~11ms faster, so it evened out, even with a high-priority thread. Dropped it.
    • photoQualityBalance="speed" on Android: this one makes flash captures faster, but photos come out ~35% smaller and ~10-13% less sharp. I don’t think it’s worth trading image quality for speed here, so I’m not going to move forward with it.
  14. cristipaval commented on Oct 16, 2026

    @cristipaval
    Contributor

    Thanks @OlimpiaZurek, I agree with dropping these

  15. OlimpiaZurek commented on Nov 3, 2026

    @OlimpiaZurek
    Contributor

    Update:

    • Checked the major regression: the metric went from 463.72ms → 836.49ms (+80.4%).
    • It looks like the jump lines up with VisionCamera V5. On iOS, p95 was around 410ms until Oct 26, hit 680ms on Oct 29 and has been 820–900ms since. The likely root cause is that v5 has no snapshot on iOS anymore, so every scan takes a full photo instead. Before, ~98% of iOS scans used the snapshot, so capture got much slower: p95 went from ~210ms to ~630ms.
    • On Android, p95 didn’t move much after the upgrade landed on Oct 26 (782ms on Oct 26, 678ms on Oct 27, 841ms on Oct 28, within the 530–830ms range of the week before). The jump came on Oct 29 (~1180ms) and looks related to more flash captures, but I can’t confirm that until the flash data from [No QA] Add flash, capture method and time since app start to the shutter-to-confirmation span #104829 reaches production. Also Use the torch and a snapshot for Android flash scans #104840 should fix the flash part.

    Checked a few possible fixes and opened 2 draft PRs:

  16. mountiny commented on Nov 3, 2026

    @mountiny
    Contributor

    Thanks! created issues for the draft prs

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

Metadata

Metadata

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions