Activation & Retention
Signup-to-Activation Funnel
for a PLG SaaS
Representative scenario based on patterns observed across multiple Series A/B PLG SaaS companies. Company details are composited and anonymized.
The Problem
86% of signups churned within 30 days. The founding team was tracking DAU and weekly actives — both looked fine. The board asked about activation rates at every all-hands meeting and nobody had a number.
Context: Series A PLG SaaS, ~$2M ARR, 22-person team. Three engineers. No dedicated data analyst.
The Approach
Audit all tracked events
Pulled the full Mixpanel event schema. Found 127 distinct events — zero named anything close to "activation." Events had been added by whoever was building each feature with no schema governance.
Correlation analysis in Snowflake
Exported all first-week events per user and joined against 90-day retention status. Ran Pearson correlation for each event against retained/churned outcome. Three events stood out clearly: report_created, team_member_invited, and integration_connected.
Define activation and build the dbt model
Defined "activated" as completing all 3 events within 7 days of signup. Built fct_activation in dbt — one row per user, activated flag, and days_to_activate. This became the single source of truth.
Build the cohort activation dashboard
Connected fct_activation to Looker. Dashboard showed: activation rate by signup week, activation rate by acquisition channel, median days-to-activate for activated vs churned users.
Identify the bug
Dashboard showed that users signing up via Google OAuth had an activation rate of 3% vs 21% for email signup. The integration_connected step was broken for OAuth signups — a configuration issue in the OAuth flow that had been silently failing.
The dbt Model
The core of the work — a single dbt model that defines activation in one place. Every downstream dashboard reads from this.
-- fct_activation.sql (dbt model)
-- Activated = completed all 3 key actions within 7 days of signup
WITH events_pivoted AS (
SELECT
e.user_id,
u.signup_at,
MIN(CASE WHEN e.event_name = 'report_created'
THEN e.event_at END) AS first_report_at,
MIN(CASE WHEN e.event_name = 'team_member_invited'
THEN e.event_at END) AS first_invite_at,
MIN(CASE WHEN e.event_name = 'integration_connected'
THEN e.event_at END) AS first_integration_at
FROM {{ ref('stg_events') }} e
JOIN {{ ref('dim_users') }} u USING (user_id)
WHERE u.signup_at >= DATEADD('day', -90, CURRENT_DATE)
GROUP BY 1, 2
)
SELECT
user_id,
signup_at,
first_report_at,
first_invite_at,
first_integration_at,
CASE
WHEN DATEDIFF('day', signup_at, first_report_at) <= 7
AND DATEDIFF('day', signup_at, first_invite_at) <= 7
AND DATEDIFF('day', signup_at, first_integration_at) <= 7
THEN TRUE ELSE FALSE
END AS activated,
DATEDIFF('day', signup_at,
LEAST(
COALESCE(first_report_at, '9999-12-31'),
COALESCE(first_invite_at, '9999-12-31'),
COALESCE(first_integration_at, '9999-12-31')
)
) AS days_to_first_key_action
FROM events_pivotedCohort rollup on top of fct_activation:
-- Weekly cohort activation rates (for Looker)
SELECT
DATE_TRUNC('week', signup_at)::DATE AS cohort_week,
COUNT(*) AS signups,
SUM(activated::INT) AS activated,
ROUND(100.0 * SUM(activated::INT)
/ NULLIF(COUNT(*), 0), 1) AS activation_rate_pct
FROM {{ ref('fct_activation') }}
GROUP BY 1
ORDER BY 1The Result
Activation rate
14%
31%
Time to insight
Unknown
6 weeks
Churn reduction
Baseline
−18% next quarter
The product team had a new question to answer: why was OAuth signup activation 3% when email signup was 21%? That question led to a 2-day fix of a broken integration step in the OAuth onboarding flow. The bug had been silently failing for 4 months.
The Non-Obvious Takeaway
The activation problem was not a product problem — it was a bug. You can't find that by looking at DAU. The cohort model created the lens that made the bug visible. Without the model, the product team would have kept rebuilding the onboarding flow.
If your team is tracking signups but can't define activation, this is a 2-week project. Book a 20-minute call — we'll scope it in one conversation.