Daily Subscriptions
Query
With
--grab all subscriptions and identify dates created, cancelled, ended, and ended. Identify type of subscription
subs AS (
SELECT
ID,
convert_timezone('UTC','America/Los_Angeles',TO_TIMESTAMP(CREATED))::DATE as created_date,
--TO_TIMESTAMP(CREATED)::DATE AS created_date,
CASE WHEN CANCELED_AT IS NOT NULL THEN convert_timezone('UTC','America/Los_Angeles',TO_TIMESTAMP(CANCELED_AT::NUMBER))::DATE END AS canceled_date,
CASE WHEN ENDED_AT IS NOT NULL THEN convert_timezone('UTC','America/Los_Angeles',TO_TIMESTAMP(ENDED_AT::NUMBER))::DATE END AS ended_date,
CASE WHEN TRIAL_END IS NOT NULL THEN convert_timezone('UTC','America/Los_Angeles',TO_TIMESTAMP(TRIAL_END::NUMBER))::DATE END AS trial_end_date,
CASE
WHEN PLAN:amount::NUMBER = 0 THEN 'free'
WHEN PLAN:interval::VARCHAR = 'year' THEN 'annual'
WHEN PLAN:interval::VARCHAR = 'month' AND PLAN:amount::NUMBER > 0 THEN 'monthly'
ELSE 'other'
END AS plan_type
FROM RAW_DB.STRIPE.SUBSCRIPTIONS
WHERE LIVEMODE = true
AND STATUS != 'incomplete_expired'
)
--Count active subscriptions by date and type as well as creations, cancellations, and conversions from trial to paid by date of event
SELECT
id.dt,
-- Daily Events
SUM(CASE WHEN s.created_date = id.dt
THEN 1 ELSE 0 END) AS new_subs,
SUM(CASE WHEN s.created_date = id.dt AND s.plan_type = 'free'
THEN 1 ELSE 0 END) AS new_subs_free,
SUM(CASE WHEN s.created_date = id.dt AND s.plan_type IN ('monthly','annual')
THEN 1 ELSE 0 END) AS new_subs_paid,
SUM(CASE WHEN s.created_date = id.dt AND s.plan_type = 'monthly'
THEN 1 ELSE 0 END) AS new_subs_monthly,
SUM(CASE WHEN s.created_date = id.dt AND s.plan_type = 'annual'
THEN 1 ELSE 0 END) AS new_subs_annual,
SUM(CASE WHEN s.trial_end_date = id.dt
AND s.plan_type IN ('monthly','annual')
AND (s.canceled_date IS NULL OR s.canceled_date > s.trial_end_date)
AND (s.ended_date IS NULL OR s.ended_date > s.trial_end_date)
THEN 1 ELSE 0 END) AS trial_to_paid_conversions,
SUM(CASE WHEN s.trial_end_date = id.dt
AND s.plan_type = 'monthly'
AND (s.canceled_date IS NULL OR s.canceled_date > s.trial_end_date)
AND (s.ended_date IS NULL OR s.ended_date > s.trial_end_date)
THEN 1 ELSE 0 END) AS trial_to_paid_conversions_monthly,
SUM(CASE WHEN s.trial_end_date = id.dt
AND s.plan_type = 'annual'
AND (s.canceled_date IS NULL OR s.canceled_date > s.trial_end_date)
AND (s.ended_date IS NULL OR s.ended_date > s.trial_end_date)
THEN 1 ELSE 0 END) AS trial_to_paid_conversions_annual,
SUM(CASE WHEN s.canceled_date = id.dt
THEN 1 ELSE 0 END) AS cancellations,
SUM(CASE WHEN s.canceled_date = id.dt AND s.plan_type IN ('monthly','annual')
THEN 1 ELSE 0 END) AS cancellations_paid,
SUM(CASE WHEN s.canceled_date = id.dt AND s.plan_type = 'monthly'
THEN 1 ELSE 0 END) AS cancellations_monthly,
SUM(CASE WHEN s.canceled_date = id.dt AND s.plan_type = 'annual'
THEN 1 ELSE 0 END) AS cancellations_annual,
SUM(CASE WHEN s.canceled_date = id.dt AND s.plan_type = 'free'
THEN 1 ELSE 0 END) AS cancellations_free,
-- Point-in-Time Counts (end of day)
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
THEN 1 ELSE 0 END) AS active_subs_eod,
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
AND s.plan_type IN ('monthly','annual')
AND (s.trial_end_date IS NULL OR s.trial_end_date <= id.dt)
THEN 1 ELSE 0 END) AS active_paid_subs_eod,
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
AND s.plan_type = 'monthly'
AND (s.trial_end_date IS NULL OR s.trial_end_date <= id.dt)
THEN 1 ELSE 0 END) AS active_paid_monthly_subs_eod,
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
AND s.plan_type = 'annual'
AND (s.trial_end_date IS NULL OR s.trial_end_date <= id.dt)
THEN 1 ELSE 0 END) AS active_paid_annual_subs_eod,
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
AND s.trial_end_date IS NOT NULL
AND s.trial_end_date > id.dt
THEN 1 ELSE 0 END) AS active_trials_eod,
SUM(CASE WHEN (s.ended_date IS NULL OR s.ended_date > id.dt)
AND s.plan_type = 'free'
THEN 1 ELSE 0 END) AS active_free_subs_eod
FROM included_dates id
left outer join subs s
ON s.created_date <= id.dt
WHERE id.dt <= CURRENT_DATE
GROUP BY ALL
ORDER BY 1;
Overview
Joins all live Stripe subscriptions onto the date spine to produce a daily record of subscription activity and point-in-time counts. Each row represents a single calendar date and includes both event-based metrics (things that happened on that day) and end-of-day snapshots (how many subscriptions were active at close of day).
All timestamps are converted from UTC to America/Los_Angeles before date truncation.
Depends on: included_dates (date_spine)
Plan Types
Subscriptions are classified into four plan types based on Stripe's PLAN JSON field:
| Plan Type | Definition |
|---|---|
free |
plan_amount = 0 |
monthly |
plan_interval = 'month' and plan_amount > 0 |
annual |
plan_interval = 'year' |
other |
Any subscription not matching the above |
Output Columns
Daily event metrics
Counts of subscriptions where the relevant event (creation, trial conversion, cancellation) occurred on dt.
| Column | Description |
|---|---|
dt |
Calendar date |
new_subs |
All new subscriptions created |
new_subs_free |
New free plan subscriptions |
new_subs_paid |
New paid subscriptions (monthly + annual) |
new_subs_monthly |
New monthly subscriptions |
new_subs_annual |
New annual subscriptions |
trial_to_paid_conversions |
Trials that converted to paid on dt (monthly + annual, not yet cancelled or ended) |
trial_to_paid_conversions_monthly |
Trial-to-paid conversions on the monthly plan |
trial_to_paid_conversions_annual |
Trial-to-paid conversions on the annual plan |
cancellations |
All cancellations |
cancellations_paid |
Cancellations of paid subscriptions (monthly + annual) |
cancellations_monthly |
Cancellations of monthly subscriptions |
cancellations_annual |
Cancellations of annual subscriptions |
cancellations_free |
Cancellations of free subscriptions |
End-of-day snapshot metrics
Point-in-time counts of active subscriptions at the close of dt. A subscription is active on a given date if it has not yet ended (ended_date IS NULL OR ended_date > dt).
| Column | Description |
|---|---|
active_subs_eod |
All active subscriptions |
active_paid_subs_eod |
Active paid subscriptions (monthly + annual) whose trial has ended or never existed |
active_paid_monthly_subs_eod |
Active monthly subscriptions past trial |
active_paid_annual_subs_eod |
Active annual subscriptions past trial |
active_trials_eod |
Active subscriptions still within a trial |
active_free_subs_eod |
Active free subscriptions |
Notes
- Trial conversion logic: A conversion is only counted if the subscription has not been cancelled or ended before the trial end date — i.e. the customer successfully converted to paid.
ended_datevs.canceled_date:ended_dateis used for point-in-time active counts (Stripe sets this when a subscription fully terminates).canceled_dateis used for cancellation event metrics (set when the customer cancels, which may precede the actual end date).otherplan type: Subscriptions classified asotherare included inactive_subs_eodandnew_substotals but will not appear in any plan-specific breakdowns. Worth monitoring if unexpected plan configurations appear in Stripe.