Measure paid customer retention with PostHog and Stripe
Join product activation to paid service coverage with an account-level cohort, explicit identity rules and a tested PostHog–Stripe SQL example.
Use Combined to connect what customers do in your product with what they pay for. Define activation at the account level, establish paid coverage at a baseline date, and measure how many of those same accounts remain covered later. This prevents a busy user, a free trial or an unpaid active subscription from inflating paid retention.
Start with the business decision
Ask: “Of the accounts activated in July and paying on August 1, what percentage still had paid service on September 1?” This is a cohort question. The denominator stays fixed; it does not grow when new customers buy in August.
Choose an activation event that represents product value, such as the first shared report. A pageview or login can be a useful activity signal, but it is a different definition. Agree on one event, one account boundary and one pair of observation dates before comparing teams or acquisition channels.
Connect the records the question needs
Connect PostHog and Stripe in Combined, then inspect the synced event and billing schemas. The PostHog connector reference documents Events and Persons. Stripe's reference includes customers, invoices, invoice_line_items and subscriptions.
Retain event ID, event name, event time, your stable product-account identifier and the billing-customer mapping. For paid coverage, use payment evidence and the appropriate recurring line's service interval. Stripe's invoice-level period is not the service period for each price; use the line-item period. Stripe invoice period reference.
Make the identity map explicit
A PostHog distinct ID is not automatically a company or a Stripe customer. Resolve identified users to your product account, and that account to its billing customer. PostHog can link anonymous activity after identification, so counting raw identifiers can count the same person twice. PostHog identity guidance.
The fixture deliberately includes two Atlas users and a repeated event. Activation becomes a distinct set of accounts before any billing join. Preserve multiple billing customers where the business requires them, but deduplicate account/customer pairs so a second product user does not duplicate paid coverage.
Define the metric and reporting window
Activation falls within July 1 inclusive to August 1 exclusive, UTC. A paid interval covers a checkpoint when its start is at or before that checkpoint and its end is after it. This half-open rule prevents a subscription ending on September 1 from being counted as covered on September 1.
The example requires a paid invoice and positive payment attributed to recurring service. A paid setup fee alongside a free recurring line does not establish that coverage. Zero-value invoices and open invoices do not establish paid service. Stripe can mark a send-invoice subscription active before its first invoice is paid, so subscription status alone is insufficient for this definition. Subscription lifecycle. Refund-adjusted revenue retention is a separate calculation.
Run the worked example
Three accounts activated in July. Atlas and Birch had paid service at the August baseline; only Atlas remains covered at September's checkpoint. Cedar's zero-value or unpaid invoice does not qualify, and an account activating exactly on August 1 is outside the July cohort. The retention rate is one of two paying baseline accounts: 50%.
Download the runnable SQL fixture and its expected result. The fixture uses synthetic records and normalized teaching tables. Run it in DuckDB; discover your own Combined datasets before adapting the calculation.
| Activated accounts | Paid at baseline | Retained paid | Paid retention |
|---|---|---|---|
| 3 | 2 | 1 | 50% |
Give your agent an exact assignment
Use my granted PostHog and Stripe sources through Combined.
Discover the schemas and verify the product-account/billing-customer map.
Build the distinct account cohort with first_report_shared in
[2026-07-01, 2026-08-01), UTC. Exclude staff, QA and test billing records.
At 2026-08-01 and 2026-09-01, check paid recurring service intervals:
start <= checkpoint < end, paid invoice, positive payment evidence.
Use the paid August baseline cohort as the retention denominator.
Do not infer payment from active subscription status or raw user counts.
Return cohort size, baseline payers, retained accounts, rate, exclusions,
source coverage, exact rules and the query receipt. Read only.Return supporting records and the next decision for each account. Display a bounded list while calculating over the complete dataset.
Check coverage before acting on the answer
Wait until event ingestion and billing coverage include the same checkpoints. Late identification can change historical account assignment; late payments can change the meaning of “paid by that date.” The fixture measures coverage using the available paid records, not what was known in real time at each checkpoint. For a historical point-in-time report, retain payment timestamps and identity history, then apply those cutoffs explicitly.
Combined gives your agent a managed data layer across these sources, so the next question does not require another export. Start with 5 million MAR without a card, connect your apps, and use the Claude Code walkthrough or MCP setup reference.
Sources and further reading
Explore the documentation behind this guide. Product details checked on September 10, 2026.