Event tracking naming convention developers building

Event Tracking Naming: Conventions That Scale Across Teams

Event tracking naming gets messy fast. Here’s a practical framework — object-action pattern, casing rules, properties, versioning, and a safe migration path — that scales across product, marketing, and engineering teams.

Every analytics implementation starts clean. Then a year goes by, three product squads ship features in parallel, two consultants come and go, and one morning you open your event list to find signup_complete, SignupCompleted, user-signed-up, and signup v2 (NEW) all firing at once. Nobody knows which one the funnel report is built on.

That’s the moment teams discover they had an event tracking naming problem all along — they just didn’t have enough events yet to notice. In my experience working with clients, naming chaos is the single most expensive analytics debt you can take on. Migrating it later is painful, and the wrong report shipped to a CEO is worse.

This piece is about the framework, not the buttons. We’ll cover the object-action pattern, casing trade-offs, properties, versioning, and how to migrate without burning down your historical data.

Why Event Naming Becomes a Crisis (Eventually)

Nobody breaks event naming on purpose. It happens through a predictable sequence:

  1. One developer instruments the first three events. Names are fine. No standard is written down.
  2. A second developer joins. They guess at the convention. They guess slightly differently.
  3. A PM asks for a “quick” event to track a campaign. It gets shipped as black_friday_2025_signup.
  4. The marketing team copies that pattern. Now every campaign has its own event.
  5. Six months later you have 400 events, 80 of which are near-duplicates, and your funnel queries take a paragraph of WHERE event_name IN (...) to be approximately correct.

The crisis isn’t really about names. It’s about trust. When two events that look like the same action return different numbers, every dashboard becomes suspect. People stop using the data. Decisions go back to gut — which is exactly the kind of “is anything actually working?” anxiety I’ve written about in the context of knowing whether your ads are doing anything.

The reason to invest in a naming convention before you need one is the same reason you invest in consistent UTM parameters: the cost of consistency is small upfront and enormous in retrospect.

The Object-Action Pattern

The most widely adopted convention is Object-Action: a noun followed by a past-tense verb. Signup Completed. Cart Viewed. Invoice Paid. Segment’s documentation formalised this years ago and it’s now the default mental model across most analytics vendors.

Why object-action wins:

  • Sorts alphabetically by object. All your cart events cluster together. Same for checkout, invoice, user, post.
  • Past tense removes ambiguity. Form Submit could mean the form-submit button or the action; Form Submitted only means the action happened.
  • It scales. Adding a new event is just picking the object and the action. The framework does the thinking for you.

Amplitude’s guidance flips the order — they prefer verb_noun like clicked_signup_button — and their docs are clear that the syntax matters less than the consistency. Pick one. Document it. Don’t switch.

Where teams get into trouble is sneaking properties into the event name itself:

Bad event name Why it breaks Better version
signup_completed_black_friday_2025 Campaign is a property, not an event. You’ll get a new event every promotion. Signup Completed with { campaign: "black-friday-2025" }
video_played_30s Duration is a property. You’ll need an event for every milestone. Video Played with { milestone_seconds: 30 }
SignupBtn_clicked Element ID is implementation detail. Renaming the button breaks history. Signup Started with { source: "hero_cta" }
Purchase No verb, no clarity. Was it attempted, completed, refunded? Order Completed
user_did_thing_v2 Versioning belongs in a schema field, not in the name. Thing Did with { schema_version: 2 }
page_view_pricing Page is a property of Page Viewed. Page Viewed with { page_name: "pricing" }

The rule I keep coming back to with clients: if a value could differ between two firings of the same logical action, it’s a property. Not part of the name.

Case vs Snake vs Kebab — Pick One and Stick With It

The casing debate is the analytics equivalent of tabs versus spaces. Everyone has an opinion, none of the opinions are wrong, and the only outcome that actually hurts you is mixing them.

Style Example Best fit Watch out for
Title Case (Segment-style) Signup Completed Human-readable dashboards, BI tools Spaces break in some SQL contexts; need to be quoted
snake_case signup_completed Warehouse-first stacks, SQL queries Less scannable in tool UIs that show 200 events
camelCase signupCompleted JavaScript-heavy product teams Easy to fat-finger signUpCompleted vs signupCompleted
kebab-case signup-completed Rare, sometimes URLs Many tools strip or escape the hyphen

My default recommendation for new implementations: Title Case for event names, snake_case for properties. That’s the Segment convention and it survives the journey from product code → analytics tool → warehouse → dashboard better than most alternatives. If your team is warehouse-first and writes a lot of raw SQL, all-snake is also defensible.

What matters more than the choice: write it down, put it in your README, and lint for it. I’ve seen teams reject pull requests that introduce a new casing — and that one rule alone keeps the schema clean for years.

Categories, Properties, and Versioning

Once your event names are stable, the next conversation is structure around them. Three layers worth designing on purpose:

Categories (or product areas)

Group events by product area so navigating 300 of them is bearable. Amplitude and Mixpanel both support folders or categories; Segment uses the object prefix to do the same job implicitly. A simple hierarchy might be Account → Authentication → Signup Completed. You don’t need a deep tree — two levels is usually enough.

Properties

Every event should carry the context needed to slice it later. The mistake most teams make is under-instrumenting properties because “we’ll add them later.” Adding properties is easy. Adding them retroactively to historical data is impossible.

A reasonable starter set for a B2B SaaS product:

  • user_id, account_id, plan_tier — who and what plan
  • source, medium, campaign — where they came from
  • page_path, referrer — where in the product
  • experiment_id, variant — if you A/B test
  • schema_version — see below

Versioning

Schemas drift. A field gets renamed, a value list changes, a new property becomes required — the same kind of moving-target problem that makes attribution itself so confusing in the first place.

The standard pattern from Snowplow’s schema model is to attach a version number to each event payload, so downstream consumers can branch on it: “if schema_version < 3, treat plan and plan_tier as the same field.”

You don’t need a full schema registry on day one. Even a schema_version: 1 property on every event, agreed and incremented when the shape changes, buys you most of the safety with almost no infrastructure.

How to Migrate From Chaos Without Breaking History

The hard scenario isn’t designing from scratch — it’s fixing an existing mess without losing the year of data the marketing team built dashboards on. I’ve done this several times and it always follows the same four-phase pattern:

Phase 1 — Audit. Export the full event list. Group near-duplicates manually. For each group, decide on the canonical name. The output is a spreadsheet: old name, new name, action (keep / rename / merge / drop).

Phase 2 — Dual-track. Start firing the new names alongside the old ones. Don’t kill the old events. Both flow into the warehouse for an overlap period — typically 30 to 90 days, depending on how long your reporting cycles are.

Phase 3 — Repoint reports. Update dashboards, funnels, and SQL queries to read from the new names. Validate that totals match the old reports during the overlap period (they should, within a percent or two — if they don’t, your migration mapping is wrong). This is also the moment to sanity-check anything tied to your attribution model — renamed events can quietly distort credit assignment if a touchpoint event silently changes shape.

Phase 4 — Sunset. Remove the old event firing from code. Mark old events deprecated in the tool. Keep the historical data — never delete it. Future analyses can UNION across old and new with a CASE mapping if needed.

The thing most guides don’t tell you: budget for Phase 2 to drag. Stakeholders find a dashboard they forgot existed, ask why a number changed, and you’re explaining the migration again. Padding the dual-track window is cheaper than rushing it.

Documentation That Survives Team Turnover

An event taxonomy that lives in one person’s head dies the day they leave. The fix is boring: a written tracking plan, owned by someone, reviewed quarterly.

The minimum useful document is a spreadsheet (or Notion table, or git-tracked YAML — the format matters less than the existence). For each event, capture:

  • Event name — exact string as it fires
  • Description — one sentence, plain English: what user action causes this?
  • Where it fires — page, component, or trigger
  • Owner — which team or person is responsible
  • Properties — name, type, example value, required/optional
  • Status — active / deprecated / planned
  • Schema version — current version number

Tools like Avo, Iteratively, and Mixpanel’s Lexicon exist to manage this — they’re useful at scale, but a well-maintained spreadsheet beats a neglected tool every time. The thing that makes a tracking plan survive is not the platform; it’s the rule that no new event ships without a row in the doc. Enforce that in code review and you’ve solved most of the problem.

This becomes especially important when you start running funnel-leak analyses or form-drop-off investigations — the analyst doing the work has to be able to look up exactly what an event represents without asking three people.

Common Naming Mistakes That Snowball

A few patterns I’ve watched bite teams more than once:

Treating event names as labels. The event name is a key, not a description. Long, prose-y names like User Clicked The Big Blue Signup Button On Pricing Page are unscannable and lock implementation details into your schema forever.

Tracking implementation, not intent. Events should describe what the user did, not how the code did it. dom_click_button_42 tells you nothing useful. Pricing CTA Clicked tells you what to do with the data.

Inventing a new event for every variant. Variants are properties. If you’re A/B testing the signup button, the event is still Signup Started — the variant goes in { experiment_variant: "B" }.

Firing the same logical event from multiple places without standardising. If Signup Completed can fire from the web app, the mobile app, and a server-side webhook, all three must use exactly the same name and the same required properties. Otherwise your “total signups” report is a lie.

Letting non-engineers name events on the fly. Marketing wants to track a webinar registration. They open GTM and create webinar_reg_OCT24_final2. It works. It also enters production schema unsupervised. The fix is gatekeeping: tracking changes go through the same review process as code. The same principle applies one layer up to landing-page conversion events and checkout abandonment tracking — both areas where ad-hoc naming tends to accumulate fastest.

Not classifying events by tier. Not every event matters equally. A useful triage is to mark events as core (drive funnel reports — change with caution), supporting (used in ad-hoc analyses), or diagnostic (debugging only — can churn freely). This affects how strict your review is. For deciding which deserve the core tier, the primary vs secondary conversions framework is the same logic applied to events.

Frequently Asked Questions

How many events should we track?

Fewer than you think. Most products run perfectly well on 20-50 well-named events with rich properties. If you’re approaching 200 events for a single product, you’re almost certainly conflating properties into event names. The healthier shape is fewer events, more properties.

Can we just rename events in the analytics tool’s UI?

Most tools let you alias or rename events in the interface — Amplitude and Mixpanel both support this. It helps for cleanup but doesn’t fix the underlying instrumentation. The new name is a display label; the raw event still fires under the old name. For a permanent fix, update the code and run the dual-track migration.

What about Google Analytics 4? Doesn’t it have its own conventions?

GA4 ships with recommended event names (sign_up, purchase, add_to_cart) in snake_case. If GA4 is your primary tool, follow their convention — it unlocks better default reports. The principles in this article (object-action, properties for variants, versioning) still apply; only the casing changes.

How do we handle events fired both client-side and server-side?

Same name, same required properties, one source of truth for the schema. Document where each event can fire so analysts know whether to expect it from web, mobile, server, or all three. Server-side events are usually more reliable; if both fire for the same action, decide explicitly which one is authoritative and deduplicate downstream.

Is it worth paying for a tracking plan tool?

Only when manual maintenance breaks down — typically past 100 events or 5+ contributors. Below that, a shared spreadsheet plus a code-review rule does the job for free. Above that, tools like Avo, RudderStack, or Mixpanel Lexicon start to earn their keep by validating events against the plan at instrumentation time.

Bottom Line

Event tracking naming is one of those problems where the technical answer is easy — pick a convention, document it, enforce it — but the organisational answer is what actually matters. The teams I’ve seen do this well treat the event taxonomy as a shared product, not as an engineering side-project. Someone owns it. Changes go through review. New hires read the doc on day one.

If you’re starting fresh: Object-Action, past tense, Title Case for names and snake_case for properties, schema_version on every payload, and a written plan from event #1. If you’re cleaning up an existing mess: audit, dual-track for 30-90 days, repoint reports, sunset the old. Either way, the goal is the same — when someone asks “how many signups did we have last month?”, everyone in the room is looking at the same number.

That number is what analytics is actually for. Everything else, including this article, is just plumbing.

Leave a Reply

Your email address will not be published. Required fields are marked *