Tensor LabsTENSORLABS

Your growth chart is counting the same person twice

Count people, not devices, and let the graph rewrite yesterday

July 6, 20263 min read3 sectionsBy Ahmed Abdullah
Your growth chart is counting the same person twice

Introduction

Marketing closed the quarter celebrating 9,400 new signups. Fourteen hundred of them were the same people who signed up last year, back on a new phone, counted again like strangers.

Nobody was lying. The tracking was working exactly as installed. Every event pipeline, whether it runs on Segment, RudderStack, or a homegrown collector, hands each device an anonymous ID the first time it shows up. Clear your cookies, reinstall the app, switch from laptop to phone, and you are a fresh anonymous ID with no history. If the user never logs in on the new device before the dashboard query runs, the company meets you for the second time and calls it growth.

The damage is symmetrical and quiet. New-user counts inflate. Churn inflates too, because the old identity goes silent and looks abandoned. Retention understates, acquisition cost per "new" user flatters the worst channels, and the activation funnel celebrates people who activated two years ago. Every metric downstream of "who is this" inherits the error.

(The user in the churn cohort had not left. He had bought an iPhone.)

A device is not a person, and most analytics stacks count devices.

The graph that rewrites yesterday

The fix is identity stitching, and the mechanism is worth understanding precisely because it is not exotic. You maintain an identity graph: a mapping table in the warehouse, Snowflake or BigQuery or Postgres, it does not matter, where every alias a person has ever carried points to one canonical person ID. Device IDs, anonymous cookie IDs, email addresses, login IDs, all edges in the same graph.

The edges come from deterministic moments. A login event ties an anonymous ID to a user ID. A purchase ties an email to a device. Each of those observations is a join key, and the graph absorbs it. No probabilistic guessing, no machine learning, just bookkeeping that most companies never sat down to do.

The part that changes the numbers is retroactive merging. When the graph learns today that anonymous device 7f3a belongs to a customer from 2024, every historical event from that device is re-attributed to the canonical person. Sessions get rebuilt. Cohorts get recomputed. The dbt model that produces your metrics reads from the stitched graph, not the raw event stream, so yesterday's report is allowed to become more true overnight.

The graph rewrites yesterday every time it learns something today, and that is a feature.

What it looks like when the counting is honest

Open-source Snowplow ships this pattern in its standard web model. RudderStack publishes identity-stitching dbt packages you can read in an afternoon. The technique is a solved problem in public; what is scarce is the decision to route every metric through it.

We built this graph for a subscription product recently, three tables and two incremental dbt models, nothing heroic. Their monthly user count dropped 14 percent the day it went live, which sounds like bad news until you notice what else moved. Churn fell by nearly a third, because the "churned" users had been sitting in the active column under new IDs the whole time. Reported reactivations, the cheapest revenue a subscription company has, tripled, because reactivation is literally invisible without stitching. The growth chart got smaller and the business got better, in the same week, from the same data.

That is the trade on offer. Numbers that are somewhat lower and entirely defensible, or numbers that are flattering and quietly fictional, and a board meeting where someone eventually asks why 60,000 users produce revenue that looks like 41,000.

If your user counts have never survived a reconciliation against billing, the gap is probably not small, and finding out is a two-week project, not a quarter. At TensorLabs we wire identity graphs into existing warehouses without replatforming anything, and the first stitched report tends to pay for the engagement by itself. Count people, not devices. The devices were never going to renew.