Grain logomark
Back to blog

Event Tracking Best Practices for Product Teams

A no-nonsense guide to naming conventions, property schemas, and tracking plans that scale. Stop drowning in messy event data.

Grain Team

Grain Analytics4 min read

Bad event tracking is worse than no event tracking. At least with no tracking, you know you're guessing. With messy tracking, you think you have answers — but they're wrong.

Here's how to build a tracking system that actually works.

Naming conventions#

This is the single most important decision you'll make. Pick a convention and enforce it ruthlessly.

Use object-action format#

Name events as object_action:

page_viewed
button_clicked
form_submitted
project_created
user_invited
payment_completed

Not clicked_button, not ButtonClick, not user clicked the signup button. Consistent object_action with snake_case.

Why this matters#

When you have 200 events (and you will), you need them to be sortable and searchable. Object-action format means all page events group together, all form events group together.

Compare:

❌ Random naming
click_signup
UserRegistered
page - pricing viewed
completed checkout
form_submit_contact

✅ Object-action, snake_case
signup_clicked
user_registered
page_viewed
checkout_completed
contact_form_submitted

Track events without writing code

Grain's point-and-click event capture lets you instrument any element on your site — no developer tickets, no GTM configuration. Clean event data from day one.

Try it free

Property schemas#

Events without properties are almost useless. page_viewed tells you nothing. page_viewed with { path: "/pricing", referrer: "google", duration: 45 } tells you a story.

Required properties for every event#

Every event should include:

  • timestamp — When it happened (usually handled by your analytics SDK)
  • page_path — Where it happened
  • session_id — Which session it belongs to

Event-specific properties#

Keep properties flat (no nesting), use consistent types, and be specific:

{
  "event": "project_created",
  "properties": {
    "project_name": "My App",
    "template_used": "blank",
    "team_size": 3,
    "is_first_project": true
  }
}

Property naming rules#

  1. snake_case — Always. teamSize and team-size and Team Size are the same thing named three different ways.
  2. Boolean prefixes — Use is_ or has_: is_first_project, has_team.
  3. No PII — Never track emails, names, or phone numbers in event properties. Use anonymized IDs.
  4. Enums over free textplan_type: "growth" not plan_type: "Growth Plan (Annual)".

Building a tracking plan#

A tracking plan is a spreadsheet (or document) that lists every event your product tracks. It's the source of truth.

What to include#

ColumnExample
Event namecheckout_completed
DescriptionUser completes payment flow
TriggerPayment confirmation page loads
Propertiesamount, currency, plan_type, is_annual
OwnerGrowth team
Added2026-01-15

Start small#

Track 15-20 events, not 200. You can always add more. You can never clean up a mess of 500 poorly-named events without breaking dashboards.

Focus on:

  1. Core conversion events — The 5-7 events in your primary funnel
  2. Feature adoption events — Key features you want users to discover
  3. Error events — When things go wrong (payment failures, form errors)

Common mistakes#

Tracking everything#

"We'll just track every click and figure it out later." You won't. You'll have a database full of button_clicked events with no context, and nobody will know what any of them mean six months from now.

Inconsistent implementations#

Developer A uses signupCompleted, Developer B uses signup_complete, Developer C uses user_signed_up. Now you have three events that mean the same thing and none of your dashboards are accurate.

Solution: the tracking plan is reviewed in PR. No event gets shipped without being in the plan.

Tracking PII in properties#

Passing email: "user@example.com" in event properties seems harmless until your analytics database is subject to a data access request and you have to find and delete every instance across millions of events.

Use anonymous user IDs. Always.

Not validating events#

Add validation at the SDK level. If an event isn't in your tracking plan, log a warning in development. This catches typos and unauthorized tracking before it ships.

Maintenance#

Quarterly audit#

Every quarter, review your events:

  • Which events have zero volume? Remove them.
  • Which events have inconsistent property values? Fix them.
  • Which events are missing properties that would make them useful? Add them.

Deprecation process#

When you remove an event:

  1. Mark it as deprecated in the tracking plan
  2. Remove it from the codebase
  3. Update any dashboards or alerts that reference it
  4. Keep the historical data (don't delete it)

The payoff#

Clean event tracking isn't glamorous work. But it's the foundation everything else is built on. Your funnels, dashboards, A/B tests, and product decisions are only as good as the data feeding them.

Start with a clean foundation

Grain gives you structured event tracking with point-and-click capture, automatic property schemas, and a tracking plan that scales. No messy migrations later.

Try it free

Invest the time upfront. Your future self will thank you.

Related articles