PostHog / PostHog/posthog

Billing usage/spend charts: selected series silently switches to a different product when the date range changes

Open
#85,581 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Bug description

On /organization/billing/usage (and the spend tab), hiding series so that only one product is visible and then changing the date range can silently switch the visible series to a different product. The chart then shows another product's numbers under the user's intended selection, with no visual indication anything changed.

How to reproduce

  1. Open Organization → Billing → Usage.
  2. In the data table, untick every series except one (e.g. a mid-list product).
  3. Change the date range to a period in which the set of products with usage differs (e.g. a product had no usage in the new range, or a new one appears).
  4. The remaining visible series is now a different product than the one selected.

Same behavior on the Spend tab.

Root cause

The billing service assigns each series a positional id: it builds series only for usage types that have data in the requested range, sorts the keys, and numbers them with enumerate (usage) / a running counter (spend). So id is "index within this particular date range", not a stable product identifier.

The frontend then persists the user's selection by that positional id:

  • frontend/src/scenes/billing/billingUsageLogic.ts — the userHiddenSeries reducer is a number[] of series ids whose only handler is toggleSeries; it survives setDateRange reloads and is not cleared by resetFilters either.
  • frontend/src/scenes/billing/BillingLineGraph.tsx — hides via visibility.excluded: hiddenSeries.includes(s.id) and colors by getSeriesColor(s.id).
  • frontend/src/scenes/billing/BillingDataTable.tsx — checkbox state, row dimming, and ribbons are keyed by record.id as well.
  • frontend/src/scenes/billing/billingSpendLogic.ts — identical pattern for the spend chart.

When the date range changes and the set of present usage types shifts, the ids re-enumerate and the persisted hidden set now points at different products.

Impact

Org admins reading usage/spend can draw wrong conclusions about what they're being charged for — the chart quietly relabels the data they filtered to. Workaround is to re-tick the series after every date change. The underlying data is correct; only the selection mapping is wrong.

Suggested fix (frontend-only)

The API response already includes stable identifiers per series (label, breakdown_value), so no billing-service change is needed:

  1. Key userHiddenSeries by a stable series key (serialized breakdown_value, falling back to label) instead of the numeric id, in both billingUsageLogic.ts and billingSpendLogic.ts (toggleSeries, emptySeriesIDs, finalHiddenSeries, toggleAllSeries).
  2. Update BillingLineGraph.tsx / BillingDataTable.tsx to exclude/dim by that key (coloring can stay on id, since chart and table ribbons derive it from the same response and stay consistent per render).
  3. Clear the selection on resetFilters.
  4. Add logic tests: toggle a series → reload with a shifted series set → the same products remain selected (no such tests exist today).

Additional context

Reported by a customer via support. Internal references (PostHog staff only): support ticket 68008, self-driving inbox report (P2, ready). Relevant history: series selection introduced in a710a6250 (#32031), current chart rendering from 5ce37d37e9 (#77178).

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 frontend/src/scenes/billing/billingUsageLogic.ts and billingSpendLogic.ts, then trace the selection props in BillingLineGraph.tsx and BillingDataTable.tsx. Read the existing reducers and add logic tests that reload a shifted series set after toggling a product. Done means the same products remain selected across date-range changes and resetFilters clears the selection.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
analytics, frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.