Analytics Event Naming Conventions: The Complete Guide
Ask five engineers how to name the same event and you'll get five incompatible answers. Here's the convention system that actually holds up across platforms, team sizes, and time.
Ask five engineers how they'd name an analytics event for a user adding an item to a cart. You'll get five different answers: AddToCart, add_to_cart, cart_item_added, CartAdd, ecommerce.cart.add. They're all reasonable. They're all incompatible.
When there's no agreed convention, naming decisions get made in the moment - by whoever is writing the ticket, the engineer implementing it, or the analyst querying the data weeks later. The result is an event registry that nobody fully trusts.
This guide covers the patterns that actually hold up across platforms, team sizes, and time. Not rules for the sake of rules - conventions that make your tracking plan a reliable source of truth instead of an archaeology project.
Why naming conventions matter more than you think
Analytics event names aren't just labels. They become the raw material for every dashboard, funnel analysis, A/B test, and ML feature your team builds. Once an event name ships to production, changing it means breaking historical data or running two event names in parallel - neither of which is pleasant.
Bad naming compounds silently. A single ButtonClicked event on a product with 50 button types forces every analyst to write the same filter logic repeatedly. Inconsistent casing between platforms (iOS sends PurchaseComplete, Android sends purchase_complete) fragments cohort data. Ambiguous past vs. present tense ("clicked" vs. "click") creates subtle disagreements about when events fire.
Good naming is cheap to get right the first time. It's expensive to fix later.
The core decision: what naming pattern to use
Most teams land on one of three patterns. Here's what each looks like in practice:
Object-action (recommended)
Structure: [Object] [Action] - the thing, then what happened to it.
Cart Item AddedSubscription CancelledReport ExportedOnboarding Step CompletedAPI Key Created
This pattern reads naturally in English, sorts objects together in alphabetical event lists, and makes the subject of each event unambiguous. It's the pattern used by Segment, Amplitude's documentation examples, and most mature analytics teams.
Action-object
Structure: [Action] [Object] - verb first.
Added Cart ItemCancelled SubscriptionExported Report
Some teams prefer this because it mimics natural English commands. The downside: event lists sorted alphabetically group all "Added" events together, then all "Cancelled" events - making it harder to find everything related to a specific object like Cart or Subscription.
Namespace-prefixed
Structure: [namespace].[object].[action] or [namespace]_[object]_[action].
checkout.cart.item_addedbilling.subscription.cancelledplatform.api_key.created
Useful for large products with distinct domains or multiple teams contributing events. The namespace prevents collisions and makes events self-documenting. The tradeoff is verbosity - names get long, and the period separator can cause issues in some query tools.
Pick one pattern and document it. Which pattern matters less than consistency. A team using action-object everywhere is in far better shape than a team where half the events are object-action and the other half are namespaced.
Casing: snake_case vs. Title Case vs. camelCase
This is the most common source of cross-platform fragmentation. iOS developers tend toward PascalCase. Backend engineers tend toward snake_case. JavaScript developers are split between camelCase and everything else.
The analytics industry has largely converged on two options:
- Title Case with spaces -
Cart Item Added. Most human-readable in dashboards, works well with Amplitude, Mixpanel, and most BI tools that display event names directly to analysts. - snake_case -
cart_item_added. Preferred by engineers, easier to write as a constant in code, no ambiguity about word boundaries.
Whatever you choose, enforce it for every platform. The worst outcome is iOS using CartItemAdded and Android using cart_item_added - they won't be recognized as the same event unless your pipeline normalizes them, and even then you've introduced a hidden transformation layer that future teammates don't know exists.
If you're building a new tracking plan from scratch, Title Case with spaces is the better default. It's the most readable in the tools where analysts actually spend time.
Tense: past tense wins
Use past tense for events. An event records something that happened - it fires after the action is complete. So: Subscription Cancelled not Cancel Subscription, Form Submitted not Submit Form.
Present tense and imperative forms ("Click", "Submit", "Cancel") can imply intent rather than completion, which is ambiguous. Did the event fire when the user clicked, or when the server confirmed the action? Past tense removes that ambiguity.
The exception: screen and page views. These are usually named in the present: Home Screen Viewed, Pricing Page Viewed. "Viewed" is past tense but the subject is the page itself - this is consistent with how Segment and Amplitude document screen events.
Granularity: how specific should event names be?
This is where most teams make a mistake in one of two directions.
Too generic: Button Clicked, Link Tapped, Action Taken. These tell you nothing without filtering on a property. Your analysts will write WHERE button_name = 'Add to Cart' in every query, which means the event name itself is doing no useful work.
Too specific: Red Add to Cart Button Clicked on Mobile Homepage Hero Section. This encodes implementation details into the event name. When the button color changes or it moves to a different section, the event name becomes a lie.
The right level of specificity is the action, not its visual implementation. Cart Item Added is correct. The context (where, from which surface) belongs in properties: source: "homepage_hero", platform: "mobile". The name captures what happened; properties capture the context.
Properties: the other half of the naming problem
Events have names; events also have properties. The same conventions apply - and the same inconsistencies cause the same problems.
Standard conventions for properties:
- Use snake_case for property keys:
user_id,plan_type,item_count. This is the near-universal standard in data pipelines, SQL, and analytics tools. - Use consistent value formats. If
plan_typecan be"free","pro", or"enterprise"- document the allowed values. Don't let iOS send"Free"while Android sends"free". - Use boolean properties rather than string flags.
is_trial: truenottrial_status: "active". - Use ISO 8601 for timestamps in properties.
started_at: "2026-03-24T10:30:00Z"notstart_time: "March 24". - Use IDs not display names for references.
workspace_id: "ws_abc123"is stable;workspace_name: "Acme Corp"changes.
Common mistakes and how to avoid them
Abbreviations
Avoid them. usr_reg_cmplt saves nothing; it costs every future analyst who encounters it. Write out the words: User Registration Completed.
Encoding the platform in the name
Don't do iOS Cart Item Added or Web Subscription Cancelled. Platform belongs in a property: platform: "ios". Events that encode the platform can't be used for cross-platform funnels without union queries.
Duplicates with different names
Purchase Completed and Order Placed are the same event with two names. This happens when two teams instrument the same action independently. A central tracking plan prevents it; a spreadsheet doesn't.
Vague actions
User Interacted, Feature Used, Action Occurred. These events exist because someone wanted to track "engagement" without deciding what that means. They generate high event volume and zero signal. Name the specific interaction.
Locking conventions in with a tracking plan
Conventions documented in a wiki page or Notion doc have a half-life of a few months. New engineers don't read them. Contractors don't know they exist. The tracking plan drifts.
The more durable approach is to make the convention machine-readable: a centralized tracking plan registry where every event is defined with a name, tense, casing, and required properties - and where new events are reviewed before they ship. Code generation takes this further by removing the manual step entirely. If the event name in the registry is Cart Item Added, the generated SDK method is trackCartItemAdded() - not whatever the next engineer felt like typing.
That's the difference between a convention and an enforced standard. Conventions require discipline. Enforced standards require a tool.
A naming convention checklist
Before you ship an event, run it through this:
- Does the name follow the agreed pattern (object-action, action-object, or namespaced)?
- Is the casing consistent with every other event in the registry?
- Is the verb in past tense?
- Is the name free of platform, device, or visual implementation details?
- Does a similar event already exist with a different name?
- Are all property keys in snake_case?
- Are enum property values documented and lowercase?
- Are all required properties present?
Eight questions. They take under a minute. They prevent years of technical debt.
Getting your team aligned
The hardest part of naming conventions isn't deciding on a standard. It's getting twelve engineers across three time zones to follow it consistently in a fast-moving codebase.
The practical path: start with your next sprint, not a retroactive cleanup. Define the convention, add it to the definition of done for any ticket that touches analytics, and use code review to catch deviations. Once the new events are clean, backfill the old ones opportunistically when you touch them anyway.
If you're ready to move beyond conventions-on-paper, Ordaze gives you a structured tracking plan registry where every event is versioned, every property is typed, and generated code enforces the naming standard at compile time. The codebase scanner can show exactly which events are implemented correctly and which are drifting.
Try Ordaze free - no credit card required.
Ready to bring structure to your analytics events?
Try Ordaze free →