PWA install banner + install analytics

Merged
FR
6d ago
+570-1

What & why

Second slice of the mobile PWA work (follows #654). Until now nothing invited phone users to install abode, and Android's share-sheet saving only works once it's installed.

  • Install prompt capture. beforeinstallprompt can fire before hydration, so instrumentation-client.ts captures it into a small store (src/lib/pwa/install-prompt.ts), which suppresses Chrome's mini-infobar so our UI can offer the prompt instead.
  • InstallAppBanner on the dashboard, shown only on touch devices that aren't already running the installed app:
    • Android: the native prompt behind an "Install" button.
    • iOS: the Share → Add to Home Screen steps.
    • Dismissing it, or declining the native prompt, snoozes it for 30 days (localStorage, best effort).
  • Platform detection goes through useSyncExternalStore with a null server snapshot, so nothing reads navigator during render and hydration can't break.
  • Analytics:
    • Every event gets a display_mode super-property (standalone / browser).
    • New events: app_installed, install_banner_shown, install_banner_install_clicked, install_prompt_result (outcome), install_banner_dismissed.

Checklist

  • User-facing change → added/updated a PostHog event (and a funnel/insight for a new flow), or N/A — events added; funnel to create in PostHog: install_banner_shown → install_banner_install_clicked → install_prompt_result (accepted) / app_installed
  • User-facing or service change → docs updated, or N/A — README features, saving-from-your-phone help page
  • New error paths report via captureServerException / the error boundary, or N/A — N/A
  • New behavior is covered by tests, or N/A — install-prompt.test.ts, use-install-option.test.ts, install-app-banner.test.tsx (RTL, per branch), plus a story
  • If this fixes a recurring defect, considered a guardrail via the learn skill, or N/A — N/A

Notes

  • Visually checked the banner in both variants (dark/light, 390px). Not tested on real Android or iOS hardware.
  • Onboarding milestone: the existing save_from_phone milestone already points at the help page, which now covers installing.

Generated by Claude Code