# Mobile-web app-install takeover — prototype + dev handoff

**Goal:** lift app adoption among mobile-web account-portal visitors from 25% → 50%+.
**Core rule:** lead with the $10 claim, support with the benefit bundle, never headline convenience.

## The prototype

- **Live (branch preview, auto-updates):** https://cometeer-git-promo-placeholder-toantron.vercel.app/promo/
- **After merge:** https://cometeer.toan.design/promo/
- Deep-linkable: `?v=a|b` (variant) and `?c=1|2|3` (copy direction), e.g. `/promo/?v=b&c=2`
- The dark **control bar** at the top is prototype-only chrome: variant switch, copy switch, ↻ replay. Strip it entirely in production.
- Single file: `promo/index.html`. Brand tokens mirrored from `app/index.html` `:root`; fonts via `/_fonts/cometeer.css`; app-store badge component reused verbatim from the try.cometeer.com landing page.

## What ships

**Variant A — sticky bottom banner** (`.app-banner`)
- ~84px row (within the 72–88px spec) + a transparent brand-yellow fade above (`--banner-fade`), safe-area inset for the iOS home indicator
- App icon (real export: `assets/cometeer-app-icon.png`) + one 7-word reward-led line + CTA pill + dismiss × (44px hit area)
- Slides up 400ms after load; never obstructs the page's primary CTA
- On dismiss, a smaller persistent **FAB** ("Get the app", app icon, shine sweep) takes its place bottom-right

**Variant B — full-screen interstitial** (`.interstitial`)
- Pops **1s after page load**; passport-yellow, matches try.cometeer.com
- Phone screenshot → headline → support line → App Store / Google Play badges → "Maybe later" (pinned with the badges in a fixed bottom bar with the yellow fade on mobile); dismiss × top-right (44px)
- Desktop/tablet (≥720px): phone sits left of the copy, two columns
- The FAB is persistent in this variant (no other always-on CTA)
- Note: the ticket's eyebrow + 3 benefit chips were deliberately removed in review (declutter pass); benefits live in the support line

**Copy matrix** (switchable, direction 1 recommended)

| Dir | Banner line [CTA] | Interstitial headline / support |
|---|---|---|
| 1 Reward | You have $10 waiting in the app. [Claim it] | Your $10 is waiting. / Claim it in the app, then use it on your next box. |
| 2 Unlock | Early drops, alerts, and $10 to start. [Unlock] | First access, plus $10 to start. / Limited roaster drops go live in the app before anywhere else — plus $10 off to get you started. |
| 3 Ritual | Build your box in half the taps. [Get the app] | Your box, in your pocket. / Swap coffees, shift deliveries, track your box — in seconds. There's $10 in there for you too. |

**Links:** store badges deep-link to their store directly (App Store `id6738394746`, Play `com.cometeer.acrolith`); single CTAs marked `data-store` resolve iOS/Android by user agent.

## Production implementation notes (the important stuff)

1. **Carry the $10 through the store — deferred deep links.** "Claim it" → a bare store listing drops the promise thread at install. Use Branch / AppsFlyer OneLink carrying `variant`, `copy_direction`, and customer ID so (a) the reward auto-applies on first app open and (b) the experiment is attributable end-to-end. Without this the 25%→50% lift can't be measured or fully realized.

2. **Consider a post-task trigger as a third cell.** 73% of portal visitors come to *edit their subscription*. A 1s takeover intercepts them before they've done that. Worth testing: fire the interstitial on the **save-confirmation moment** instead of page load — same asset, user just succeeded, the "do this faster in the app + $10" pitch lands as relevant instead of as a wall. Guardrail metric either way: subscription-edit completion rate must not drop.

3. **Analytics: impressions + dismissals, not just clicks.** Every promo element carries `data-promo="<placement>"` (`banner-cta`, `interstitial-ios`, `interstitial-android`, `fab`) — the click hook is stubbed at the bottom of `index.html`. Production needs three events per variant/copy: `promo_impression`, `promo_dismiss`, `promo_store_click`, keyed by customer ID.

4. **Frequency caps (relaxed in the prototype for reviewability):**
   - Once per session — including when the prompt is *ignored*, not just dismissed (track an `autoshown` session flag)
   - 3 lifetime max per customer, then permanently suppressed
   - Dismiss is one tap and persists
   - Suppress entirely for existing app users — gate on a `has_app_session` flag at customer-ID level (server-side, not UA sniffing)

5. **Experiment-design caveat: the FAB is part of both treatments.** In Variant A it appears after dismissal, in B it's persistent. So cell "A" is really "banner + FAB". Either include the FAB in both arms of the test plan or add an A-without-FAB cell.

6. **A11y for production:** trap focus inside the interstitial while open (Tab currently escapes to the page behind); add a `prefers-reduced-motion` fallback for the banner slide-up (badges/FAB shine already have one); Esc-to-close and focus restore are already implemented.

7. **No dark patterns (spec + kept):** no countdown timers, no fake close, dismiss always visible, "Maybe later" is a real exit.

8. **iOS Smart App Banner stacking — needs a product call.** The page ships `<meta name="apple-itunes-app" content="app-id=6738394746">` (same as try.cometeer.com), so **Safari-on-iOS users see Apple's native install banner at the top *and* our prompt at the bottom simultaneously**. Upside: the native banner shows "OPEN" for users who already have the app — free installed-state handling Safari won't give our JS. Downside: two install prompts on one screen, and the OS banner is an uncontrolled install path in *both* test cells. Decide: keep both (accepted double-prompt, note it in the test plan), or drop the meta tag from the portal and rely solely on the tested prompt. There is no reliable JS way to detect whether the Smart App Banner is showing.
