Skip to content
fitme·story
Case studies
v7.10 · 2 min read · 2026-06-23

Funnel Analysis Dashboards — running the canonical funnels against live GA4 (v7.10)

The backlog framed this (RICE 6.0) as "just needs GA4 funnel definitions wired" — but a Phase 0.1 reality-check found the 5 canonical funnel definitions had already shipped, prose-only, and had never been run against live data. Scope was reframed to the net-new work: run the 5 funnels against live GA4 (28d via the ga4 MCP — the first real readout), extract the prose into a machine-readable data contract, and map each funnel to the kill-criteria it unblocks. 3 of 5 funnels turned out computable; the highest-leverage unblock is not code but a GA4 custom-dimension registration (operator action).

Funnels run against live data
0 of 5
definitions existed as prose in the runbook but had never touched GA4 — no drop-off was ever computed.
Funnels with computed live drop-off
3 of 5
F1/F2/F5 computed from the 28d GA4 window; extracted into funnel-definitions.json + guarded by a test.
What do T1 / T2 / T3 mean?
T1Instrumented — from a ledger/commit
T2Declared — stated, not measured
T3Narrative — estimate from memory

Funnel Analysis Dashboards

Status: shipped 2026-06-23 (PR #799). An Enhancement of analytics-observability.

The reality-check that reframed the scope

The backlog framed this (RICE 6.0) as "just needs GA4 funnel definitions wired." A Phase 0.1 reality-check found the 5 canonical funnel definitions had already shipped (2026-06-01, in the GA4 funnels runbook) — prose-only, and never run against live data.

So the scope was reframed to the genuinely net-new, agent-ownable work:

  1. Run the 5 funnels against live GA4 (28d via the ga4 MCP) — the first real readout.
  2. Extract the prose defs into a machine-readable data contract (docs/product/funnel-definitions.json).
  3. Map each funnel to the kill-criteria it unblocks; guard the contract with a test.

What the live data showed

FunnelLive verdict
F1 ActivationPartial — strong top (open→view 91.5%); conversion workout_complete=0 (TestFlight)
F2 Onboarding drop-offEvent-level — viewed 379 → completed 193 = 50.9%; per-step blocked on custom dims
F3 Smart RemindersBlocked — all alert events 0 (TestFlight not shipped)
F4 Web→AppDeferred — no install bridge
F5 UCC observabilityPartial — warning 5 → load 9; conversion event never fired

3 of 5 computable; only onboarding-completion (F2) has a live kill-criterion signal today. The validation test earned its keep on day one — it caught a real mislabel during development.

Outcome

test_funnel_definitions.py 10/10, broader scripts suite 34/34, integrity-check 0 findings / 0 advisory, and no new analytics events. Three operator follow-ups (O1 custom dimensions, O2 next TestFlight, O3 taxonomy rows) were recorded in operator-actions-pending.md §E.

Cross-references

Honest disclosures
  • Per-step (step_index) ratios are NOT yet measurable — the Data API returns INVALID_ARGUMENT until the operator registers those params as GA4 custom dimensions (operator action O1). Reported as narrative where estimated; event-level aggregates are T1.
  • F3 Smart Reminders and F1 conversion read 0 because those events only fire in a shipped TestFlight build (operator action O2) — not a regression, a not-yet-shipped surface.
  • A taxonomy drift surfaced as a side effect: home_readiness_alert_* / home_trend_alert_* exist in AnalyticsProvider.swift but not in analytics-taxonomy.csv (operator action O3, out of scope here).
Kill criterion · not fired
  • If <3 of 5 funnels have any computable live drop-off, defer the analysis report until after the TestFlight ship and reduce scope to the machine-readable defs only.