Mobile app template
The Mobile consumer-app template — an early-retention model built around the D1/D7/D30 cohort curve, engagement rhythm, push, and monetization.
Pick Mobile consumer app when you create a project (or apply the template from
Settings → Templates) and your dashboard is built around early retention —
the D1/D7/D30 curve that decides whether a new install becomes a habit or an
uninstall — plus engagement rhythm, push, and monetization. It's the one Tier-C
vertical with a genuinely new scoring shape: the cohort_retention op.
Set installed_at (a date) and the push_opt_in flag via
the account upsert. If you don't set
installed_at, retention falls back to an app_installed
event, then to the account's creation date.
Event components map a raw value to a 0–100 score at their good
/ warn thresholds. Early retention scores the share of elapsed
D1/D7/D30 milestones the user survived, and push opt-in is a fixed flag
score. Overall health is the weight-proportional average, banded Healthy ≥ 80 ·
Watch ≥ 60 · Risky ≥ 40 · Cold < 40.
Retention & engagement
The core of mobile health. Early retention is the defining signal — the first days decide everything. Pair it with session frequency and recency (is the habit forming and holding?) and feature depth (did they find the value?).
Evidence: mobile retention is steep — median D1 ~26%, D7 ~13%, D30 ~7% (MWM) — so early-lifecycle retention has to be scored explicitly, not inferred from lagging engagement.
Early retention (D1 / D7 / D30)app_openShare of the D1/D7/D30 milestones the user stayed active for.
Higher is betterweight 18
app_openShare of the D1/D7/D30 milestones the user stayed active for.
- How we collect it
- Send `app_open` on each launch and set `installed_at` on the account (via the account upsert) — or send an `app_installed` event; the op falls back to account creation.
- How to read it
- For each elapsed milestone (D1, D7, D30) from install, the user 'survived' if still active at or beyond it. Score is the share of survived milestones, 0–100. A cohort too young to have reached any milestone is skipped.
- How to analyze it
- Early retention is the defining mobile churn signal — benchmarks sit around D1 ~26%, D7 ~13%, D30 ~7%, so the first days decide the relationship.
- What to do
- Invest in first-session activation and a D1/D7 re-engagement loop; the early curve is where the most users are saved.
- Tune it
- Change the milestone offsets (`retentionDays`) to match your app's natural habit loop — a daily app cares about D1/D3/D7, a weekly one about D7/D14/D30. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Session frequency (30d)sessionApp sessions in the last 30 days.
Higher is bettergood ≥ 20warn ≤ 3weight 14
sessionApp sessions in the last 30 days.
- How we collect it
- Send `session` on app opens (SDK auto-capture maps this by default).
- How to read it
- Raw value is the session count. 20+ scores 100; ≤ 3 scores 30. Frequency is the core habit signal.
- How to analyze it
- Consumer apps live or die on habit — a user who opens often has embedded the app into their routine.
- What to do
- Build daily-value hooks (streaks, fresh content, reminders) for low-frequency users before they lapse.
- Tune it
- Set the band to your app's natural cadence; a utility opened weekly reads differently from a daily social app. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Days since last openapp_openRecency of app opens.
Lower is bettergood ≤ 3 dayswarn ≥ 14 daysweight 14
app_openRecency of app opens.
- How we collect it
- Derived from the latest `app_open` event.
- How to read it
- Raw value is days since the last open. ≤ 3d scores 100; ≥ 14d scores 30. Growing gaps precede uninstall.
- How to analyze it
- Recency is the earliest dormancy signal — the slide from daily to weekly to never is where churn happens.
- What to do
- Trigger a push or email as recency crosses your habit interval, before the app slips off the home screen.
- Tune it
- Tighten for daily-habit apps; loosen for episodic ones. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Feature / screen depthfeature_usedShare of distinct features / screens reached.
Higher is bettergood ≥ 40%warn ≤ 10%weight 10
feature_usedShare of distinct features / screens reached.
- How we collect it
- Send `feature_used` (or map screen views) as the user explores the app.
- How to read it
- Raw value is the share of the configured feature set touched. Broad exploration scores high.
- How to analyze it
- Breadth of value found early strongly predicts retention — users who only see one screen rarely stay.
- What to do
- Guide new users to a second and third core feature; surface undiscovered value in-app.
- Tune it
- Set `totalFeatures` to your app's core surface count so the ratio is meaningful. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Push & monetization
The retention levers. Push opt-in and engagement are among the strongest controllable retention drivers; paywall conversion marks the users who've committed with their wallet.
Evidence: apps using push see up to ~3× retention and global opt-in is ~67%, but over-notifying drives uninstalls — so opens, not sends, are what count (vmobify). Monetized users retain materially better than free users.
Push opt-inpush_opt_inWhether push notifications are enabled.
Pass / failweight 8
push_opt_inWhether push notifications are enabled.
- How we collect it
- Set the `push_opt_in` account flag via the account upsert when the user grants permission.
- How to read it
- Enabled → 100; disabled/unknown → the floor (45 in the template). A fixed-score flag.
- How to analyze it
- Apps using push see up to ~3× retention, and global opt-in is ~67%; opt-in is a powerful, controllable retention lever.
- What to do
- Earn the opt-in with a well-timed, value-first prompt; win back opted-out users through other channels.
- Tune it
- Raise the absent floor if your app doesn't rely on push; keep it below present so opt-in still matters. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Push engagement (30d)push_openedOpened push notifications in the last 30 days.
Higher is bettergood ≥ 5warn 0weight 8
push_openedOpened push notifications in the last 30 days.
- How we collect it
- Send `push_opened` when a notification is tapped (map `notification.opened`).
- How to read it
- Raw value is the opened-push count. 5+ scores 100; none scores the floor.
- How to analyze it
- Engaged notifications pull users back — but over-notifying drives uninstalls, so opens (not sends) are what matter.
- What to do
- Optimize for relevance and timing over volume; prune notification types with low open rates.
- Tune it
- Set the band to your healthy monthly push-open rate. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Paywall conversion (90d)iap_purchaseIn-app purchases ÷ paywall views, as a %.
Higher is bettergood ≥ 5%warn 0%weight 10
iap_purchaseIn-app purchases ÷ paywall views, as a %.
- How we collect it
- Send `paywall_view` when the paywall shows and `iap_purchase` on purchase; the `ratio` op divides them.
- How to read it
- Raw value is view-to-purchase conversion. ≥ 5% scores 100; 0% scores 30.
- How to analyze it
- Monetized users retain and churn less — a paying user has committed in a way a free user hasn't.
- What to do
- Test paywall placement, timing, and offer; a user who sees the paywall but never converts is unmet intent.
- Tune it
- Anchor `good`/`warn` to your own conversion benchmark, which varies widely by app category. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Friction & trend
What breaks the habit. Crashes and frustration drive uninstalls fast, and a sharp week-over-week activity drop is an early dormancy signal that moves before the user formally leaves.
Evidence: friction and crashes are leading uninstall drivers on mobile; week-over-week engagement decline reliably precedes churn.
Crashes & frustration (30d)frustration_scoreRage-clicks, crashes, and errors captured by the SDK.
Lower is bettergood 0warn ≥ 8weight 10
frustration_scoreRage-clicks, crashes, and errors captured by the SDK.
- How we collect it
- SDK auto-capture maps rage-clicks and errors to `frustration_score`.
- How to read it
- Raw value is the friction count. 0 scores 100; 8+ scores 30.
- How to analyze it
- Friction drives uninstalls fast on mobile — a crash at the wrong moment can end the relationship instantly.
- What to do
- Prioritise crash and rage-click hotspots; a smooth app is table stakes for retention.
- Tune it
- Lower warn for polished apps where any friction is notable. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Activity drop (WoW)any eventWeek-over-week drop in event volume.
Lower is bettergood ≤ 20warn ≥ 60weight 8
any eventWeek-over-week drop in event volume.
- How we collect it
- Computed from every event on the account — no dedicated event needed.
- How to read it
- Raw value is the percentage drop vs. the prior week. A small drop scores high; near-total silence scores low.
- How to analyze it
- A sharp week-over-week drop is an early dormancy signal — the habit is breaking before the user formally leaves.
- What to do
- Re-engage as the drop steepens; pair with recency for the full dormancy picture.
- Tune it
- Loosen for spiky, episodic apps where week-to-week swings are normal. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Sending the data
Install date and push opt-in go through the account upsert; the rest are events. Send events via the SDK or the HTTP API; map your names in Settings → Event map.
| Signal | Kind | How to send |
|---|---|---|
installed_at | account date | PUT /api/accounts/{id} → attributes.installed_at |
push_opt_in | account flag | PUT /api/accounts/{id} → attributes.push_opt_in = true |
app_open | event | on each launch |
session | event | on each session |
push_opened | event | on each notification tap |
iap_purchase / paywall_view | events | on purchase / paywall shown |
app_installed | event | on first install (a fallback source for the install date when installed_at isn't set) |
Common raw names (app.open, notification.opened, iap.purchase,
paywall.shown, …) are pre-mapped, so most SDKs resolve out of the box.
Optional signals
These aren't scored by the default template but are recognized signals you can send and later build a custom component on:
| Signal | When to send | Why it's useful |
|---|---|---|
app_uninstalled | On uninstall (e.g. push-token invalidation) | The terminal churn event — a definitive confirmation for reporting or a hard-cold rule. |
push_enabled | When the user enables push in-app | An event-based alternative to the push_opt_in account flag if you'd rather track opt-in over time than as a single state. |
Next
- Enrich account data — set
installed_at,push_opt_in,kind: "person". - Build a custom dashboard — retune weights, thresholds, and retention milestones.