Cometly
AcademyModule 03 · Product-Led Growth Reports
PLGSetupLesson 3.6·8 min read

Avoiding plan upgrade misattribution

Why your reports show twice as many trials as they should.

This is one of the most common silent bugs we see in PLG attribution setups. The reports look fine, the numbers grow predictably, and three months later someone notices that trial counts in Cometly are double the trial counts in Stripe. Almost always, it’s plan upgrades getting tagged as trials.

Why this matters

When the bug is live, every plan upgrade in your customer base looks like a new trial conversion. Channel ROAS gets inflated by 30–80%, lookalike seeds become contaminated with existing customers, and the platforms’ algorithms start optimizing toward upgrades instead of new acquisition.

Section 01

The right trigger

Use Stripe’s `customer.subscription.updated` event, filtered to records where `previous_attributes.status = 'trialing'` and `current.status = 'active'`. That filter only fires on real trial-to-paid conversions, not on plan changes.

Tag plan upgrades and downgrades as their own events (Upgrade, Downgrade, Plan Changed). That way the attribution doesn’t collide with the new-customer events, and you can build separate expansion-revenue reports for upgrades.

  • Trigger: `customer.subscription.updated`
  • Filter: `previous_attributes.status` = 'trialing' AND `status` = 'active'
  • Tag plan changes (`previous_attributes.plan` ≠ current `plan`) as Upgrade/Downgrade
  • Audit monthly against Stripe’s native trial-conversion count
Section 02

Auditing the setup

Run a monthly audit: count Stripe trial-to-paid conversions in the last 30 days from Stripe’s native dashboard, then count Cometly Trial Converted events in the same window. They should match within 1–2%. A 10%+ delta means something is misfiring — either the filter is too loose (counting upgrades) or too tight (missing real conversions).

Common pitfalls

What to watch for.

  • Using payment amount as a trial-conversion filter

    Plan upgrades match payment-amount filters. Always use the status-transition filter instead.

  • Letting upgrades and new customers share an event

    Expansion revenue and new acquisition are different problems. Separate them at the event level.

  • Skipping the monthly audit

    These bugs are silent. You only catch them with a routine reconciliation against Stripe’s native dashboard.

Key takeaways

Recap.

  • Use `subscription.updated` with the `previous_attributes.status = trialing` filter
  • Tag plan upgrades and downgrades as their own events for accurate expansion-revenue reporting
  • Never use simple payment-amount filters as a trial-conversion signal — they capture upgrades too
  • Audit historical trials monthly to catch silent regressions in event firing
  • Keep a 'No Source' bucket visible so you can spot tracking gaps fast
Put it into practice

Build this report inside your own Cometly workspace.

Most lessons can be wired up in a single 30-minute onboarding call. Connect your stack live and walk away with a working dashboard.