PostHog / PostHog/posthog

Revenue Analytics counts canceled Stripe subscriptions as active when subscription rows are stale

Open
#58,148 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

feature/revenue-analytics
Dominant language
Python
Stars
39.9k
Forks
3.4k
Avg merge
6h 51m
Merged PRs (30d)
232

Description

Bug

Revenue Analytics' subscription, customer, and LTV charts can be wrong when the data warehouse holds stale Stripe subscription rows. Subs canceled after their initial sync stay counted as active forever; churn never increments; LTV stays empty. MRR / Gross revenue look correct.

Repro

  1. Set up a Stripe data warehouse source with the default Subscription schema (append-only incremental, keyed on created).
  2. Have at least one subscription that gets canceled in Stripe after it was first synced.
  3. Open Revenue Analytics, look at any period after the cancellation.

Expected: the canceled sub falls out of "active" and appears in churn after its ended_at.
Actual: it stays counted as active forever; churn never increments; LTV chart is empty.

Root cause

Stripe subscription sync is append-only by created timestamp (posthog/temporal/data_imports/sources/stripe/settings.py:78, source.py:262 - supports_incremental=False, supports_append=True). The DWH only fetches subs with new created values; existing rows are never re-fetched. When Stripe populates ended_at on cancellation, our copy of the row stays with ended_at = NULL.

The Revenue Analytics subscription view passes ended_at straight through (products/revenue_analytics/backend/views/sources/stripe/subscription.py:55), and the metrics query treats NULL ended_at as still active (_period_gteq_expr in revenue_analytics_query_runner.py:469-482 short-circuits to true when isNull(left)).

Result:

  • Subscription / customer counts inflate as canceled subs accumulate
  • Churn check (_period_eq_expr on ended_at) never fires, so churned_customer_count = 0
  • LTV multiIf returns NULL when churned_customer_count = 0, so the series is empty (revenue_analytics_metrics_query_runner.py:204-209)

MRR is unaffected because it's driven by invoices; when billing stops, no new invoices arrive and MRR drops naturally.

Fix options

  1. Add a merge / upsert sync mode for Stripe subscriptions in the data warehouse so existing rows update.
  2. Auto-schedule periodic full refresh of the Subscription schema as a workaround.
  3. Land the durable fix in Customer Analytics if Revenue Analytics stays in maintenance mode.

Customer workaround today: trigger a full refresh on the Subscription schema in DWH settings, and repeat periodically.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with posthog/temporal/data_imports/sources/stripe/settings.py and source.py, then read products/revenue_analytics/backend/views/sources/stripe/subscription.py and the expressions in revenue_analytics_query_runner.py. Compare the available fix options and trace how ended_at reaches the metrics queries. Done means canceled subscriptions are no longer active, churn increments after ended_at, and LTV is populated.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
analytics, data-engineering
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.