What This Dashboard Measures
This dashboard tracks how widget activation (setting up a Bible verse widget on the home/lock screen) affects retention (coming back to the app) and L3 (using the app 3+ days per week). All data is US-only.
Cohort Definitions
Every widget user is assigned to exactly one cohort type based on their behavior:
| Cohort | Definition | Platform |
|---|---|---|
| iOS Scratch | Set a widget AND scratched it within ±7 days | iOS only |
| iOS No Scratch | Set a widget, never scratched | iOS only |
| iOS Later Scratched | Set a widget, scratched it later (outside ±7 day window) | iOS only |
| Android Widget | Set any widget | Android |
| Baseline iOS / Android | Never set a widget | Both |
Scratch = the interactive widget where users physically scratch to reveal a verse. Time-based: a user who scratched within 7 days before or after setting the widget counts as “scratch.”
Cohort week = the Monday-start week when the user first set their widget. All week numbers (W1, W2, etc.) are relative to this date.
How Cohorts Are Built (Technical Detail)
Step 1: Identify Widget Setters
Source: northstar.widget_events_1y — all GA4 widget events for US users in the last year.
iOS set events: did_set_daily_verse_widget → daily_verse, did_set_hourly_verse_widget → hourly_verse
Android set events: widget_daily_verse_small_set, widget_daily_verse_large_set → daily_verse; widget_hourly_verse_small_set, widget_hourly_verse_large_set → hourly_verse
Scratch event: widget_scratched (iOS only)
For each user × widget_type combination, we take MIN(event_date) as their first_widget_date.
Step 2: Classify Scratch Behavior
Find each user’s first scratch date, then classify based on the time gap between widget set and first scratch:
- ios_scratch: Scratched within ±7 days of setting widget
- ios_later_scratched: Scratched, but outside the ±7 day window
- ios_pure_no_scratch: iOS, set widget, never scratched
- android_verse: Android (no scratch feature)
Why ±7 days? Scratch happening near the widget set date indicates early engagement with the interactive feature. Later scratchers found it organically — a separate “power user” cohort.
Mutually exclusive — each user appears in exactly one type (verified: only 709 of 3.3M users, 0.02%, edge cases).
Step 3: Assign Placement
Source: widget_family field in widget set events:
accessoryRectangular→ lock screensystemMedium/systemLarge→ home screen
Classification per user (mutually exclusive): home_only, lock_only, both, unknown (older events, Android).
Step 4: Assign Demographics
- Age: From
sandbox_analytics.users.age— 13-17, 18-24, 25-34, 35-44, 45-54, 55+, unknown - Premium status: User has ANY Adapty event in
bc-ads-tester.subscription.adapty_realtime. Lifetime flag. - Onboarding passed: User exists in
data_warehouse.onboarding_passed(16.8M users, full history since 2023). - Platform: From
northstar.user_platform_lookup. Normalized to iOS/Android in activation tables.
Step 5: Cohort Week & Baseline
Widget users: cohort_week = DATE_TRUNC(first_widget_date, WEEK(MONDAY))
Baseline users: US users from sandbox_analytics.users who never appear in widget_events_1y. Cohort week = account creation week. Baseline starts April 7, 2025.
How Retention Is Counted
For each cohort user, check if they had any screen activity in week N after their cohort_week. Source: northstar.user_daily_activity (126M rows, full history). Incremental daily updates from user_daily_screens.
How L3 Is Counted
Same as retention but higher bar: 3+ distinct days with real screen activity in the week. “Real screen” = unique_screens > 1 OR screens_visited[0] != 'splash_screen'. Excludes splash-only sessions (37% of daily entries). Uses DELETE+INSERT for the current week (L3 status changes as the week accumulates).
How Widget Entry Is Counted
Users who came back specifically by tapping the widget (deeplink entry). Identified via data_warehouse.deeplink_open: deeplink_source = 'pre_widget' AND deeplink_type = 'splash' AND deepLink contains "type":"daily" or "type":"hourly". iOS only.
NOT deeplink_source = 'widget' — that’s the panic button / affirmation widget.
Population Summary (April 15, 2026)
| Group | Users | % Passed Onboarding |
|---|---|---|
| iOS Scratch | ~172K | ~95% |
| iOS No Scratch | ~2.4M | ~78% |
| iOS Later Scratched | ~58K | ~93% |
| Android Widget | ~280K | ~72% |
| Baseline iOS | ~2.1M (ob passed) | 48% of total |
| Baseline Android | ~550K (ob passed) | 45% of total |
Widget Types & Placement
- Daily Verse / Hourly Verse — the two widget types. A user can have both; in
widget_cohort_sizes, they appear as separate rows per type. - Placement: Home Only, Lock Only, or Both — mutually exclusive per user. Determined by the
widget_familyfield:accessoryRectangular= lock screen,systemMedium/systemLarge= home screen.
Retention (How It’s Calculated)
Definition: A user is “retained” in week N if they had any screen activity in that week (including splash screen).
Formula: retention_rate = active_users / cohort_size × 100
Week numbering: W1 = first full week after widget set (or install for baseline). W0 = the install/widget-set week itself (partial).
L3 (How It’s Calculated)
Definition: A user is “L3” in week N if they visited 3 or more distinct days with real screen activity in that week.
“Real screen activity” = the user visited at least one screen beyond just splash_screen. This is critical because 37% of daily “active” entries are splash-only — a user tapped their widget, saw the splash screen, and closed the app without actually using it. These ghost sessions are excluded from L3 but included in retention.
Formula: l3_rate = l3_users / cohort_size × 100
Key difference from retention: Retention = any activity (low bar). L3 = 3+ real-screen days (high bar). L3 is the North Star metric.
Entry Retention & Entry L3
Definition: Measures users who returned to the app specifically via tapping the widget (deeplink entry), not through any other path.
How we identify widget entries: deeplink_source = 'pre_widget' AND deeplink_type = 'splash' AND the deepLink JSON contains "type":"daily" or "type":"hourly".
iOS only — deeplink tracking data is only available for iOS.
NOT deeplink_source = 'widget' — that’s the panic button / affirmation widget, a different feature.
Onboarding Passed Filter
Default: ON (showing only users who completed onboarding).
Why it matters: Without this filter, the baseline includes users who bounced during onboarding and never entered the app. This makes widget lift look artificially high. With the filter on:
- Baseline W1 retention: ~34% (post-onboarding) vs ~18% (all users)
- This gives a fair apples-to-apples comparison
Toggle to “All” to see the unfiltered view including onboarding bouncers.
Widget Activation by Age
Definition: What percentage of new US users in each age group set up a widget.
Source: northstar.widget_activation_by_age — a materialized table with COUNT(DISTINCT user_id) for both numerator (widget setters) and denominator (all new users). No double-counting possible.
Pie chart: Distribution — what share of widget activators are in each age group.
Bar chart: Rate — what % of new users in each age group activate.
Data Pipeline
| Time (UTC) | What |
|---|---|
| ~06:00 | GA4 daily export — raw events available |
| 07:00 | data_warehouse pipelines — screens, deeplink_open, onboarding_passed |
| 07:00 | sandbox_analytics refresh — user_daily_screens, users |
| 08:00 | northstar_daily_refresh — L3 smiling curves, placements |
| 09:00 | widget_daily_refresh — all tables on this dashboard |
Dashboard refresh: Hourly via GitHub Actions → Cloudflare Pages
Premium Status
A user is “premium” if they have ANY of these Adapty events: trial_started, trial_converted, subscription_started, subscription_renewed. This is a lifetime flag — once premium, always premium in this data.
Data Quality Notes
- widget_type overlap: A user with both daily + hourly verse appears in both
widget_typerows inwidget_cohort_sizes. Summing across widget_types inflates by ~10%. The activation table uses DISTINCT user_id to avoid this. - Current week L3 is incomplete — accumulates Mon→Sun, recomputed daily. The dashboard cuts off the latest partial week.
- Android has no entry data — deeplink tracking is iOS only.
Tables Used
| Table | Rows | What |
|---|---|---|
widget_cohort_sizes | 18K | Denominators for all widget curves |
baseline_cohort_sizes | 3.3K | Denominators for baseline curves |
widget_retention | 369K | Weekly retention (any activity) |
baseline_retention | 70K | Baseline weekly retention |
widget_entry_retention | 141K | Retention via widget tap (iOS) |
widget_l3_curves | 369K | Weekly L3 (3+ real-screen days) |
baseline_l3_curves | 70K | Baseline weekly L3 |
widget_entry_l3 | 141K | L3 via widget tap (iOS) |
widget_activation_by_age | ~2K | Clean activation rates by age |
user_daily_activity | 126M | Daily screen activity with splash flag |
Last updated: April 15, 2026