Guide

Dashboards do not create insight. Events do — if they are named consistently, attached to a stable identity and queried with the right population in the denominator. An event is a timestamped record that something happened: signup_completed, project_created, checkout_paid. An event property is structured context (plan=pro, source=invite). A user property is state on the person or account (country, role, created_at).

A tracking plan is a spreadsheet or schema registry: event name, description, when it fires, required properties, owner and status (planned / live / deprecated). It is the contract between product, engineering and analytics. Do not let tool choice delay it.

The big idea

Pick one naming style and enforce it in code review:

  • object_action in past tense: invite_sent, invoice_paid, file_uploaded. button_clicked is vague; purple_cta_clicked dies when the button color changes.
  • Prefer user-intent nouns over UI chrome: upgrade_started beats a CSS class.
  • Version breaking changes: search_performed → search_performed_v2 only when properties change meaning; otherwise add optional properties.

Always collect: timestamp, user_id / anonymous_id, session_id if you use sessions, platform, app_version and object ids (project_id, org_id). Often: source / medium / campaign on acquisition events, plan, is_trial, experiment assignment ids. Rarely: free-text dumps, PII you do not need or high-cardinality noise (mouse_x).

Users arrive anonymous, then log in. If you do not alias or merge identities, a single person becomes two users and your activation funnel lies.

  1. SDK assigns anonymous_id (cookie / device).
  2. On login, send identify(user_id) and merge history.
  3. All subsequent events carry both ids until merge completes.

Merging late (only after week 2) orphans early events. Fix identity in the first session path, and run a weekly check: % of signup_completed events with a resolvable user_id should be near 100%.

Quality checks: volume monitors (a sudden 50% drop in page_viewed is usually a broken SDK); property fill rates (if plan is null on 40% of upgrade_started, segmentation is garbage); duplicate / double-fire from React Strict Mode or a poorly guarded useEffect; schema validation in CI.

Warehouse-native setups scale better for complex joins. Product analytics UIs (Amplitude, Mixpanel, PostHog) win for self-serve funnels. Many teams run both. Critical money or entitlement steps should fire server-side; browsers ad-block. Compare checkout_paid client vs server weekly — drift over a few percent deserves a bug ticket.

Walking through it

Review tracking PRs like public interfaces. Name events in the PR description with the product question they answer ("supports 'do invited users activate faster?'"). When a PM asks "what's our activation rate?", answer with the definition first ("% of signups who create a project within 7 days"), then the number.

Keep PII and card data out of the event stream. Pass opaque ids; enrich in the warehouse under access control.

Common mistakes

  • UI-chrome event names. The button will change; the intent will not.
  • Merging identity after week 2. Early funnel steps become orphans.
  • No fill-rate monitors. You discover plan is 40% null when a board review goes sideways.

Check yourself

  1. Why is purple_cta_clicked a bad event name?

It is UI chrome. When the button color changes, history breaks. Prefer upgrade_started.

  1. What weekly check catches a broken identity merge?

Percent of signup_completed events with a resolvable user_id should be near 100%.

Key takeaways

  • Events need stable names, useful properties and early identity merge.
  • A tracking plan plus volume and fill-rate monitors is cheaper than reconstructing history.
  • Server-side for money; client-side is fine for cosmetic UI — compare the two for checkout_paid.

Further learning

PostHog documentation: Product analyticsProduct analytics helps you understand how people use your product. Use the events you capture to explore adoption, conversion, and retention with…posthog.com

Next: turn those events into funnels.