The event taxonomy conversation nobody wants to have

Product analytics fails at the naming stage, months before anyone looks at a funnel. The two-hour conversation that prevents it, and the rules that last.

Product analytics projects rarely fail at the analysis. They fail eight months earlier, in the twenty minutes where somebody decided what to call the events.

The symptoms arrive later and look like analysis problems. Two events that mean the same thing. An event that fires twice on iOS and once on Android. A property called type that holds four unrelated concepts depending on where it was sent from. A funnel that cannot be built because the middle step was never instrumented and nobody noticed until it was needed.

None of that is fixable in the warehouse. You can clean it up, at cost, forever. You cannot recover an event that was never sent.

The conversation#

The fix is a two-hour meeting held before any instrumentation, with three people in the room: someone from product who knows what decisions the data has to support, someone from engineering who will actually write the calls, and someone from analytics who will have to query it.

Missing any of the three produces a predictable failure. Without product, you instrument what is easy rather than what matters. Without engineering, you design a taxonomy that cannot be implemented in the codebase you have. Without analytics, you produce something that is technically consistent and miserable to query.

The agenda is short:

  1. What decisions do we want this data to support? Write down five, specifically.
  2. What questions would answer those decisions?
  3. What is the minimum set of events and properties that answers those questions?
  4. What are the names?
  5. Who owns this document, and what is the process for adding to it?

Step three is where the discipline is. The instinct is to instrument everything on the basis that storage is cheap. Storage is cheap; attention is not. An event stream with four hundred event types has the same practical value as one with none, because nobody can hold it in their head and nobody trusts any individual event.

Rules that make names last#

A handful of conventions do most of the work. Which convention you pick matters far less than picking one and holding to it.

Object then action, always in that order. checkout_completed, not completed_checkout. When you have two hundred events sorted alphabetically, object-first groups them usefully and action-first does not.

Past tense for things that happened. application_submitted, not submit_application. Events record history; naming them as commands invites confusion with the API calls that trigger them.

One casing rule. snake_case throughout is our default because it survives being loaded into a warehouse without quoting. Whatever you pick, apply it to event names and property names alike.

No client-specific prefixes. Not ios_login_completed and web_login_completed. One event, login_completed, with a platform property. Otherwise every funnel you build is a union of platform variants, and you will forget one.

Properties describe, events happen. If you find yourself creating loan_approved_small and loan_approved_large, the size belongs in a property. The rule of thumb: if two events would always be analysed together, they are one event with a property.

Reserve a small set of standard properties on every event. Timestamp in UTC, user identifier, session identifier, platform, app version, and a source. Standard properties are what make cross-event analysis possible without a join per question.

The tracking plan is a real artefact#

The output of that meeting is a tracking plan, and it needs to be a live document rather than a memory of a conversation.

A workable one is a table with a row per event and these columns:

ColumnWhy it is there
Event nameThe contract
DescriptionWhat it means in business terms, one sentence
TriggerThe precise moment it fires, in the code
PropertiesName, type, example value, required or optional
OwnerWho to ask when it looks wrong
StatusProposed, live, deprecated
AddedDate, and the version it shipped in

The Trigger column is the one that gets skipped and the one that prevents the most pain. "Fires when the user submits the application" is ambiguous. "Fires on successful HTTP 200 from POST /applications, before the redirect" is not. The difference between those two is a five percent discrepancy that somebody will spend a fortnight investigating in eighteen months.

Governance without ceremony#

The plan will drift unless adding to it costs something small but non-zero.

What works: a pull request against the tracking plan, reviewed by whoever owns it, merged before the instrumentation ships. Not a committee. Not a form. One reviewer whose job is to ask whether this event duplicates an existing one and whether the name follows the rules.

What also works, and is worth the setup: schema validation at ingestion. Reject or quarantine events whose properties do not match the declared schema, and alert on the rejections. This turns a silent data quality problem into a loud engineering problem, which is where it belongs.

The failure mode to design against is the well-meaning engineer under deadline pressure adding checkout_complete because they could not remember whether the existing one was checkout_completed. Validation catches that in minutes. A quarterly audit catches it in a quarter.

Where identity fits#

The other thing to settle in that first meeting is identity, because it is nearly impossible to retrofit.

Three questions:

  • What identifies an anonymous visitor, and how long does that identifier persist?
  • What identifies a known user, and when do the two get stitched together?
  • What happens to events sent before the stitch?

The last one determines whether you can ever build a true acquisition funnel. If pre-login events are not retroactively attributed to the user once they identify, your funnel starts at login, and every question about acquisition becomes an estimate.

What it buys you#

Getting this right is unglamorous. It produces no dashboard and demos badly.

What it produces is the ability, a year later, to answer a question in an afternoon rather than a fortnight — because the events exist, they mean what they say, and the person asking does not have to first establish whether the data can be trusted.

That is the whole return. It is larger than it sounds, and it compounds.

Is this the shape of your problem?

We build agentic AI and analytics pods — analytics engineers, AI engineers and decision scientists, with a lead who has done this for thirteen years. Start with a two-week Readiness Check.