Skip to content

Switch to Classic on mWeb opens the HybridApp instead of staying in the browser #99588

Open

Description

@Julesssss

Problem

On mWeb, tapping Switch to Classic hands off to the installed HybridApp instead of staying in the browser. In-page mWeb taps should never leave the browser — see Improve app deep link behaviour and test suite.

Version Number: v9.4.51-1
Reproducible in production?: Yes
Email or phone of affected tester (no customers): [email protected]
Issue reported by: Applause Internal Team
Device used: Pixel 7 Pro/Android 17

Action Performed:
Test different sources. Precondition: Account has Switch to Classic in troubleshoot: enter in console if account doesn't show it Onyx.merge('nvp_tryNewDot', {
classicRedirect: {
isLockedToNewDot: false,
},
});
Steps:

  1. Open mweb: https://new.expensify.com/
  2. Navigate to Account - Troubleshoot - Switch to Classic

Expected Result:
mWeb tapped in-page should stay in the browser

Actual Result:
Tap on Switch to Classic open Hybrid app

Workaround:
Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari

Screenshots/Videos

Video.mp4

Solution

???

Issue OwnerCurrent Issue Owner: @aimane-chnaif

Activity

  1. self-assigned this
    on Aug 26, 2026
  2. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Aug 26, 2026
  3. MelvinBot commented on Aug 26, 2026

    @MelvinBot
    Contributor

    Issue Analysis

    Root Cause: This is an OS‑level deep‑link handoff, not an in‑page routing bug. "Switch to Classic" on mWeb navigates the browser to https://www.expensify.com/inbox?... (via openOldDotLink → asyncOpenURL, which does a top‑level _self navigation). Because /inbox is registered as a Universal Link / App Link for the installed Classic/Hybrid app on www.expensify.com, the OS intercepts that cross‑domain navigation and hands off to the native app instead of staying in the browser.

    I confirmed the live association file served from www.expensify.com/.well-known/apple-app-site-association explicitly lists /inbox and /inbox/ as matched components for the native app, and www.expensify.com/.well-known/assetlinks.json delegates handle_all_urls to the Android Classic/Hybrid package. That is exactly what pulls the tap into the app.

    This is not fixable in Expensify/App. App only claims new.expensify.com in its own native config — it neither registers www.expensify.com nor can browser JS suppress a verified OS‑level app‑link handoff. The lever is the deep‑link association config for www.expensify.com and the Classic/Hybrid app's native deep‑link configuration, both of which live outside this repo. This needs an internal engineer to exclude the in‑page mWeb transition path(s) (e.g. /inbox) from Universal Link / App Link matching, in line with the expected behavior in #98061 ("Tapping a link on mWeb expensify.com / new.expensify.com will not deep link into app").

    Investigation details

    Flow that triggers it

    1. Tap "Switch to Classic" → TroubleshootPage.tsx / DynamicExitSurveyConfirmPage.tsx:68 call openOldDotLink(CONST.OLDDOT_URLS.INBOX, true).
    2. Link.ts:86 builds https://www.expensify.com/inbox?email=....
    3. asyncOpenURL/index.web.ts runs Linking.openURL(url, '_self') — a top‑level cross‑domain nav (new.expensify.com → www.expensify.com).
    4. The OS matches www.expensify.com/inbox against the installed native app's verified associated domain and opens the app.

    Why App can't fix it

    • Android intent filters (AndroidManifest.xml) and iOS associated domains only claim new.expensify.com / staging.new.expensify.com — never www.expensify.com. The intercepting app is the installed Classic/Hybrid app.
    • There is no App‑side referrer/param trick that suppresses a verified app‑link handoff; browser JS cannot override it.

    Live config evidence (publicly served from www.expensify.com)

    • apple-app-site-association → components include {"/": "/inbox"} and {"/": "/inbox/"} (and paths lists /inbox, /inbox/).
    • assetlinks.json → delegate_permission/common.handle_all_urls for the Android Classic/Hybrid package.

    Note on verification: this behavior can only be reproduced on a physical/emulated mobile device with the Classic/Hybrid app installed — a desktop web browser has no such association and won't hand off, so it can't confirm the repro.


    Next steps: This requires a change outside the Expensify/App repo (deep‑link association config for www.expensify.com + the Classic/Hybrid app's native config). Please escalate to an internal engineer with access, ideally tracked alongside #98061.


    view run

  4. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Aug 26, 2026
  5. melvin-bot commented on Aug 26, 2026

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @QichenZhu (External)

  6. removed
    ExternalAdded to denote the issue can be worked on by a contributor
    on Aug 26, 2026
  7. deleted a comment from melvin-bot on Aug 26, 2026
  8. Julesssss commented on Aug 26, 2026

    @Julesssss
    ContributorAuthor

    Not open for external contributions

  9. aimane-chnaif commented on Aug 26, 2026

    @aimane-chnaif
    Contributor

    Please assign me here too

  10. 13 remaining items

  11. Julesssss commented on Sep 10, 2026

    @Julesssss
    ContributorAuthor

    Not overdue, in progress

  12. melvin-bot commented on Sep 15, 2026

    @melvin-bot

    @aimane-chnaif Huh... This is 4 days overdue. Who can take care of this?

  13. Julesssss commented on Sep 18, 2026

    @Julesssss
    ContributorAuthor

    I think the correct solution would be to adjust such links in a way mobile app can handle them properly (or update the app), so when someone clicks on Switch to Expensify classic, they're correctly redirected to the mobile OD.

    Coming back to this issue, is this something you would have time to work on soon @war-in?

  14. war-in commented on Sep 22, 2026

    @war-in
    Contributor

    I think wildcard deeplinks should resolve the issue - #99347
    but there are a couple of issues we encountered. Could you check those @Julesssss? 🙏

  15. war-in commented on Sep 25, 2026

    @war-in
    Contributor

    Actually they won't 😅

    But here is the PR that should - #102312

    The only caveat is that it works only on Android 15+, but I think it's fine (it doesn't work at all now and 15+ are majority of devices)

    Also, we'll have to deploy expensify.com (OD) AASA file with this change

    {
        "/": "*",
        "?": {"openInBrowser": "true"},
        "exclude": true,
        "comment": "Links opened from NewDot in the browser stay in the browser"
    },

    @Julesssss could you help with that? 🙏

  16. Julesssss commented on Sep 25, 2026

    @Julesssss
    ContributorAuthor

    The only caveat is that it works only on Android 15+

    Nice, thanks. Yeah not a problem.

    Will get to this when I have a moment

  17. melvin-bot commented on Oct 12, 2026

    @melvin-bot

    This issue has not been updated in over 15 days. @Julesssss, @war-in, @aimane-chnaif eroding to Monthly issue.

    P.S. Is everyone reading this sure this is really a near-term priority? Be brave: if you disagree, go ahead and close it out. If someone disagrees, they'll reopen it, and if they don't: one less thing to do!

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

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.MonthlyKSv2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions