Goal
When someone taps a button like Start a chat in a Maple email, it should open the Maple app if they have it installed, and the web app if they don't. Today every email link opens the browser.
How it'll work
| Where they tap |
What happens |
| Phone with the app |
The phone opens the Maple app on a new chat |
| Phone without the app |
A new chat opens in the browser |
| Desktop |
The page offers to open the desktop app ("Open Maple?"), with Open the app / Continue in browser, and falls back to the web chat after a moment |
| Signed out, anywhere |
Sign in first, then land on the new chat |
Steps (one PR each)
Details for reviewers (current state, design notes, open questions)
Current state (master at 8f770f3)
- Web: chat lives at
/. There's no /chat route and no prompt prefill.
- Signed-out users on
/ see the entry page.
/?login=true&next=… sends users to login and then back to next, which utils/internalRedirect.ts validates.
- Desktop:
- The app registers
cloud.opensecret.maple://; dev builds register .dev://.
DeepLinkHandler.tsx only handles auth?handoff_grant=… and payment links. Anything else logs "Unknown deep link type".
- iOS:
- The AASA claims only
/payment-success*, /payment-canceled* and /pricing*.
- The entitlement is
applinks:trymaple.ai only, so www.trymaple.ai links never open the app.
- Android:
tauri.conf.json has app links for the same three paths.
assetlinks.json already covers the package and its signing keys.
- Store links already exist in
src/utils/appDownloads.ts.
Design notes
- Use apex
trymaple.ai links, never www. iOS only claims the apex domain.
- Build links from an app base URL, not a hard-coded domain, so the planned move to
app.trymaple.ai is a config change.
- Before the move, add
applinks:app.trymaple.ai, and serve the link-claim files on both domains, so phones keep opening the app through the move.
- After the move,
trymaple.ai/chat redirects to the app host.
- Desktop hand-off:
- Browsers can't tell whether an app is installed, so the page tries
cloud.opensecret.maple://chat, and the browser shows its own "Open Maple?" prompt.
- It falls back to the web chat after about 1.5s, or when the user presses Continue in browser. The page can remember the choice.
- No prompt prefill (
?q=) in v1. A link that pre-fills a chat prompt is a prompt-injection path. If it's added later: fill the box only, never send, and cap the length.
- Email click tracking must be off for these links. Tracking redirects break Universal Links and App Links.
Open questions
- Is click tracking on in Resend today?
- On Windows and Linux, does the
cloud.opensecret.maple:// scheme register at install? lib.rs:366-381 logs when it doesn't.
Goal
When someone taps a button like Start a chat in a Maple email, it should open the Maple app if they have it installed, and the web app if they don't. Today every email link opens the browser.
How it'll work
Steps (one PR each)
cloud.opensecret.maple://chatandhttps://trymaple.ai/chat/chatpage: a new chat when signed in, sign in and come back when signed out, and the desktop hand-off/chatas an app link (iOS and Android)/chat. This waits until 2–4 ship and the email redesign is settled.Details for reviewers (current state, design notes, open questions)
Current state (
masterat8f770f3)/. There's no/chatroute and no prompt prefill./see the entry page./?login=true&next=…sends users to login and then back tonext, whichutils/internalRedirect.tsvalidates.cloud.opensecret.maple://; dev builds register.dev://.DeepLinkHandler.tsxonly handlesauth?handoff_grant=…and payment links. Anything else logs "Unknown deep link type"./payment-success*,/payment-canceled*and/pricing*.applinks:trymaple.aionly, sowww.trymaple.ailinks never open the app.tauri.conf.jsonhas app links for the same three paths.assetlinks.jsonalready covers the package and its signing keys.src/utils/appDownloads.ts.Design notes
trymaple.ailinks, neverwww. iOS only claims the apex domain.app.trymaple.aiis a config change.applinks:app.trymaple.ai, and serve the link-claim files on both domains, so phones keep opening the app through the move.trymaple.ai/chatredirects to the app host.cloud.opensecret.maple://chat, and the browser shows its own "Open Maple?" prompt.?q=) in v1. A link that pre-fills a chat prompt is a prompt-injection path. If it's added later: fill the box only, never send, and cap the length.Open questions
cloud.opensecret.maple://scheme register at install?lib.rs:366-381logs when it doesn't.