Event schema
Fields the query expects
| Field | Type | Why it exists |
|---|---|---|
| timestamp_utc | Timestamp | When the product event occurred. |
| user_id | Utf8 | Stable user identifier. |
| event_name | Utf8 | Stable snake_case milestone name. |
| source | Utf8 | Acquisition or campaign source. |
Copy the query
WITH events AS (
SELECT user_id, event_name, timestamp_utc
FROM product_events
WHERE timestamp_utc >= now() - INTERVAL '30 days'
),
signups AS (
SELECT user_id, MIN(timestamp_utc) AS signed_up_at
FROM events WHERE event_name = 'signup_completed'
GROUP BY user_id
),
onboarding AS (
SELECT s.user_id, s.signed_up_at, MIN(e.timestamp_utc) AS onboarded_at
FROM signups AS s
LEFT JOIN events AS e ON e.user_id = s.user_id
AND e.event_name = 'onboarding_completed'
AND e.timestamp_utc >= s.signed_up_at
GROUP BY s.user_id, s.signed_up_at
),
integrations AS (
SELECT o.user_id, o.signed_up_at, o.onboarded_at,
MIN(e.timestamp_utc) AS integrated_at
FROM onboarding AS o
LEFT JOIN events AS e ON e.user_id = o.user_id
AND e.event_name = 'integration_connected'
AND e.timestamp_utc >= o.onboarded_at
GROUP BY o.user_id, o.signed_up_at, o.onboarded_at
),
user_funnel AS (
SELECT i.user_id, i.signed_up_at, i.onboarded_at, i.integrated_at,
MIN(e.timestamp_utc) AS activated_at
FROM integrations AS i
LEFT JOIN events AS e ON e.user_id = i.user_id
AND e.event_name = 'first_value_completed'
AND e.timestamp_utc >= i.integrated_at
GROUP BY i.user_id, i.signed_up_at, i.onboarded_at, i.integrated_at
),
stage_counts AS (
SELECT 1 AS step_order, 'Signed up' AS step, COUNT(signed_up_at) AS users
FROM user_funnel
UNION ALL
SELECT 2, 'Onboarded', COUNT(onboarded_at) FROM user_funnel
UNION ALL
SELECT 3, 'Integrated', COUNT(integrated_at) FROM user_funnel
UNION ALL
SELECT 4, 'Activated', COUNT(activated_at) FROM user_funnel
)
SELECT
step_order,
step,
users,
100.0 * users
/ NULLIF(MAX(CASE WHEN step_order = 1 THEN users END) OVER (), 0)
AS conversion_from_signup_pct,
100.0 * users
/ NULLIF(LAG(users) OVER (ORDER BY step_order), 0)
AS conversion_from_previous_pct
FROM stage_counts
ORDER BY step_order;This read-only query is planned and executed against an empty typed table with Apache DataFusion 45.2.0. We review the synthetic sample output separately. Check field types, thresholds, and counting rules against your own data. Read the testing methodology.
Query result
Signup-to-activation funnel
The largest absolute loss occurs before onboarding completion, while integration remains the strongest later bottleneck.
| step_order | step | users | conversion_from_signup_pct | conversion_from_previous_pct |
|---|---|---|---|---|
| 1 | Signed up | 8 | 100 | — |
| 2 | Onboarded | 6 | 75 | 75 |
| 3 | Integrated | 4 | 50 | 66.67 |
| 4 | Activated | 3 | 37.5 | 75 |
Synthetic example output. Run the query against your own event schema and thresholds before using it for operational decisions.
Reproduce the example
Download the sample data
The JSON bundle includes the event schema with field types, reproducible input rows, exact SQL, expected output, review notes, and engine version. The CSV contains the displayed result.
How the SQL works
- 1Each CTE selects the first milestone at or after the previous eligible stage, retaining one row per signed-up user.
- 2A missing or out-of-order milestone blocks all later steps. A later valid retry can advance the user, and duplicates count once.
- 3The query reports both conversion from signup and conversion from the previous step, making total performance and the largest transition loss visible together.
- 4The event names should represent completed milestones, not page views or button clicks that do not prove the user achieved the step.
Edge cases to check
- Use a cohort window based on signup time and allow enough time for recent signups to activate.
- Events that arrive late can temporarily move users backward in a recently calculated funnel.
- Segment by acquisition source only after the total funnel has enough volume.
Recommended dashboard
- Funnel bars: users by step
- Line chart: activation rate by signup week
- Table: conversion by source, plan, or persona
Alert guidance
Use a low-urgency alert when a signup cohort's observation window has closed and activation falls below your chosen baseline threshold.
Read alert setupSet up the events this query needs
Related instrumentation and guides
Define the source data
Event schemas for this analysis
user_signed_up
An event for a completed signup, with acquisition and plan fields. Use a pseudonymous account identifier and review marketing attribution fields for privacy before collecting them.
Review schemaproduct_milestone_completed
A generic milestone envelope for stable product outcomes such as connecting a source, running a first query, or publishing a dashboard.
Review schemaContinue the analysis
Calculate weekly cohort retention
Group users by first activity week and measure the percentage returning in later weeks.
Open recipeFind features used before upgrade
Join feature events to upgrade events and rank behaviors that occur before paid conversion.
Open recipeCalculate DAU, WAU, and product stickiness
Measure daily and weekly active users together and calculate DAU-to-WAU stickiness from a consistent activity definition.
Open recipeRun it on your events
Create a table, adapt the fields, and save the result
Start free, send structured events, and use the query result as a chart, shared dashboard widget, or alert input.