A customer lifecycle connects acquisition to durable product value and commercial state. It answers more than “did the user finish onboarding?”:
- Who was eligible to start?
- Which milestones represent real progress?
- When did an account first receive value?
- Did that value lead to paid conversion and retention?
- Where did customers cancel, churn, or return?
GraphJSON does not create lifecycle stages or profiles automatically. Keep account, entitlement, billing, and cancellation state authoritative in the application, billing provider, or CRM. Send stable transitions and product facts to GraphJSON for analysis.
This recipe brings together the definitions in the Product metrics cookbook, Revenue and subscription analytics, and Account analytics and customer 360.
Define the lifecycle before the funnel#
Write a state model appropriate to the business:
eligible
→ signed up
→ trialing
→ activated
→ paid
→ retained
→ cancellation scheduled
→ churned
→ reactivated
Not every transition is mandatory. A sales-led customer may become paid before product activation. A freemium user may never enter a trial. An account can reactivate more than once.
For each state, document:
- entry event or authoritative condition
- entity grain
- effective time
- minimum observation window
- exit conditions
- allowed repeated entry
- owner and definition version
Do not infer commercial state from product inactivity.
Choose the customer grain#
For B2B products, lifecycle usually belongs to the account while onboarding actions belong to individual members:
{
"event": "onboarding_milestone_completed",
"account_id": "acct_7",
"user_id": "usr_42",
"milestone": "first_data_source_connected",
"milestone_version": 2,
"completion_id": "milestone:acct_7:first_data_source:v2",
"result": "success"
}
One administrator may connect data and another user may create the first report. Count the account as activated if the contract allows cross-member completion.
For a consumer product, user_id may be correct. Never count users in one
stage and accounts in the next.
Separate signup, trial, and eligibility#
Emit the trial decision from its authority:
{
"event": "trial_started",
"account_id": "acct_7",
"trial_id": "trial_91",
"trial_type": "business_14d",
"trial_version": 3,
"starts_at": "2026-07-10T18:00:00Z",
"scheduled_ends_at": "2026-07-24T18:00:00Z",
"eligibility_policy_version": 4,
"acquisition_channel": "organic"
}
Keep eligibility even when no trial starts. Otherwise the trial-start rate has no denominator. Common eligibility exclusions include previous trials, employees, test accounts, incompatible regions, or an existing paid contract.
Do not silently restart the trial clock when a user joins an existing account.
Use milestones that predict value#
Onboarding steps should represent durable progress:
- verified an account
- invited an appropriate teammate
- connected a real data source
- imported valid data
- configured the first workflow
- completed the first successful outcome
Avoid treating dismissing a tour, viewing a tooltip, or visiting a setup page as activation. These may be useful diagnostic events, but they do not prove value.
For every milestone, record the definition version and terminal outcome. Retries and failed attempts must not become completions.
Define activation independently#
Activation is the earliest point at which the customer receives the intended product value:
{
"event": "account_activated",
"account_id": "acct_7",
"activation_id": "acct_7:v3",
"activation_version": 3,
"activated_at": "2026-07-12T20:14:00Z",
"qualifying_outcome": "decision_ready_report_shared",
"days_since_trial_start": 2,
"calculated_at": "2026-07-12T20:20:00Z"
}
Calculate complex activation in application code or a versioned worker. Keep the contributing product facts so the result can be audited.
GraphJSON does not schedule this calculation. For recurring evaluations, use Derived events and scheduled rollups.
Model paid conversion as a billing fact#
{
"event": "account_became_paid",
"account_id": "acct_7",
"subscription_id": "sub_44",
"trial_id": "trial_91",
"plan": "business",
"currency": "usd",
"effective_at": "2026-07-20T00:00:00Z",
"billing_event_id": "stripe:evt_123"
}
The billing provider or application database remains authoritative. Decide whether conversion means checkout completion, successful first payment, contract start, or the end of a trial that rolls into paid service.
Keep “activated during trial” and “converted to paid” as separate outcomes.
Query a mature lifecycle funnel#
WITH starts AS (
SELECT
JSONExtractString(json, 'account_id') AS account_id,
min(toDateTime(timestamp)) AS trial_started_at
FROM lifecycle_events
WHERE JSONExtractString(json, 'event') = 'trial_started'
GROUP BY account_id
),
activated AS (
SELECT
JSONExtractString(json, 'account_id') AS account_id,
min(toDateTime(timestamp)) AS activated_at
FROM lifecycle_events
WHERE JSONExtractString(json, 'event') = 'account_activated'
GROUP BY account_id
),
paid AS (
SELECT
JSONExtractString(json, 'account_id') AS account_id,
min(toDateTime(timestamp)) AS paid_at
FROM lifecycle_events
WHERE JSONExtractString(json, 'event') = 'account_became_paid'
GROUP BY account_id
)
SELECT
toStartOfWeek(starts.trial_started_at, 1, 'UTC') AS cohort_week,
count() AS mature_trials,
countIf(
activated.activated_at >= starts.trial_started_at
AND activated.activated_at < starts.trial_started_at + INTERVAL 14 DAY
) AS activated_trials,
countIf(
paid.paid_at >= starts.trial_started_at
AND paid.paid_at < starts.trial_started_at + INTERVAL 21 DAY
) AS paid_trials,
activated_trials / nullIf(mature_trials, 0) AS activation_rate,
paid_trials / nullIf(mature_trials, 0) AS paid_conversion_rate
FROM starts
LEFT JOIN activated USING account_id
LEFT JOIN paid USING account_id
WHERE starts.trial_started_at < now() - INTERVAL 21 DAY
GROUP BY cohort_week
ORDER BY cohort_week
The 21-day maturity rule includes a seven-day conversion grace period after a 14-day trial. Choose a window that matches the commercial policy.
Measure time to value as a distribution#
Show median and upper percentiles, not only an average. Keep never-activated accounts in the activation rate; do not assign them an invented time to value.
Segment by event-time acquisition channel, trial version, intended use case, account size, and onboarding path. Ensure a large assisted customer is not compared directly with a self-serve individual without context.
Model cancellation and churn separately#
Cancellation intent, service end, and loss of product activity are different:
{
"event": "subscription_cancellation_scheduled",
"account_id": "acct_7",
"subscription_id": "sub_44",
"requested_at": "2026-09-03T18:00:00Z",
"effective_at": "2026-09-30T23:59:59Z",
"reason_category": "missing_capability",
"source": "self_serve"
}
{
"event": "account_churned",
"account_id": "acct_7",
"subscription_id": "sub_44",
"churned_at": "2026-09-30T23:59:59Z",
"churn_definition": "paid_service_ended",
"churn_version": 2
}
Do not send free-text cancellation feedback by default. Use controlled reason categories and keep private details in the source system.
Define winback and resurrection#
Use distinct terms:
- resurrected usage: an inactive customer resumes meaningful product use
- reactivated subscription: a churned customer becomes commercially active
- winback: a reactivation attributed to a defined intervention
Emit a new lifecycle transition for each commercial reactivation. Preserve the original acquisition date and the new effective date. Decide whether retention cohorts remain anchored to first acquisition or create a reactivation cohort.
Do not call every spontaneous return a campaign winback.
Build the lifecycle dashboard#
Show:
- eligible accounts, signups, and trial starts
- milestone completion and time between milestones
- mature activation and paid-conversion rates
- time-to-value distribution
- retention by activation path
- cancellation requests and effective churn
- resurrection and paid reactivation
- results by trial and definition version
- source freshness and reconciliation status
Pair rates with denominators. Suppress immature cohorts rather than displaying them as failures.
Launch checklist#
- Lifecycle state, product progress, and billing state are distinct.
- One durable entity grain connects every stage.
- Eligibility exists before trial-start measurement.
- Milestones represent terminal progress, not interface exposure.
- Activation has a governed version and auditable contributing facts.
- Paid conversion comes from the billing authority.
- Every rate uses a mature observation window.
- Cancellation request, service end, inactivity, and churn remain separate.
- Winback requires an explicit attribution rule.
- Dashboard totals reconcile with application and billing state.