Event contract
Fields the query expects
| Field | Type | Why it exists |
|---|---|---|
| timestamp_utc | Timestamp | Subscription event time. |
| account_id | Utf8 | Stable billing account identifier. |
| event_name | Utf8 | trial_started or subscription_started. |
| acquisition_source | Utf8 | Source captured when the trial began. |
Copy the query
WITH trials AS (
SELECT
account_id,
MIN(timestamp_utc) AS trial_started_at,
MIN(acquisition_source) AS acquisition_source
FROM subscription_events
WHERE event_name = 'trial_started'
AND timestamp_utc >= now() - INTERVAL '120 days'
GROUP BY account_id
),
paid AS (
SELECT
account_id,
MIN(timestamp_utc) AS paid_at
FROM subscription_events
WHERE event_name = 'subscription_started'
GROUP BY account_id
)
SELECT
date_trunc('week', trials.trial_started_at) AS trial_week,
trials.acquisition_source,
COUNT(*) AS trial_accounts,
SUM(CASE
WHEN paid.paid_at >= trials.trial_started_at
AND paid.paid_at < trials.trial_started_at + INTERVAL '30 days'
THEN 1 ELSE 0
END) AS paid_accounts,
100.0 * SUM(CASE
WHEN paid.paid_at >= trials.trial_started_at
AND paid.paid_at < trials.trial_started_at + INTERVAL '30 days'
THEN 1 ELSE 0
END) / NULLIF(COUNT(*), 0) AS conversion_rate_pct
FROM trials
LEFT JOIN paid ON paid.account_id = trials.account_id
GROUP BY
date_trunc('week', trials.trial_started_at),
trials.acquisition_source
ORDER BY trial_week, acquisition_source;This read-only query is planned and executed against an empty typed table with Apache DataFusion 45.2.0. The deterministic sample output is synthetic and reviewed separately; validate field types, thresholds, and business definitions against your own data. Read the testing methodology.
Query result
Thirty-day trial conversion by source
Product referrals convert at the highest rate despite having the smallest cohort.
| trial_week | acquisition_source | trial_accounts | paid_accounts | conversion_rate_pct |
|---|---|---|---|---|
| 2026-06-29 | docs | 184 | 41 | 22.28 |
| 2026-06-29 | paid_search | 310 | 37 | 11.94 |
| 2026-07-06 | product_referral | 96 | 28 | 29.17 |
Synthetic example output. Run the query against your own event schema and thresholds before using it for operational decisions.
How the SQL works
- 1The trial CTE creates one cohort record per account.
- 2The paid CTE prevents multiple subscription events from counting the same account twice.
- 3The 30-day condition keeps cohorts comparable even when eventual conversion happens much later.
Edge cases to decide
- Exclude cohorts that have not had the full conversion window before comparing final rates.
- Decide how a cancelled and restarted trial should enter the cohort.
- Persist acquisition source at trial start so later attribution changes do not rewrite history.
Recommended dashboard
- Bars: conversion_rate_pct by acquisition_source
- Trend: paid conversion by trial_week
- Table: trials approaching the end of the conversion window
Alert guidance
Use a weekly review alert when a mature cohort falls materially below its trailing source baseline.
Read alert setupPut the recipe to work
Related instrumentation and guides
Continue the analysis
Build a Signup-to-Activation Funnel in SQL
Calculate unique-user conversion through signup, onboarding, integration, and first-value milestones.
Open recipeMeasure Payment-Failure Recovery
Calculate how often failed invoices are recovered by a later successful payment attempt.
Open recipeCalculate Monthly Recurring Revenue Movement
Separate new, expansion, contraction, churn, and reactivation MRR from billing lifecycle events.
Open recipeRun it on real 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.