Tracking Agent docs

The tracking plan method behind the Tracking Agent

Every change the Tracking Agent proposes follows four design rules, prefers no change over a new event, and never renames an event in place. The rules: an event exists because someone asks a question it answers; intent and outcome come as a pair; one action from many places is one event; success and failure live on one event. Your _conventions.yaml changes the naming, not these rules.

By Ansh AgrawalUpdated

What are the four tracking plan rules?

RuleRightWrong
1. An event exists because someone asks a question it answerspost_created answers "how many posts were published last week, from which entry point, and how many failed?"sidebar_collapsed, which answers nothing anyone asks
2. Track intent and outcome as a paircheckout_started on the client and order_placed on the serverTracking only the success, so drop-off can't be measured
3. The same action from several places is one event with a propertyinvite_clicked with entry_point set to header, empty_state or settingsThree events, one per button
4. Success and failure live on one eventpayment_completed with status and failure_reasonpayment_completed plus payment_failed, so every conversion rate needs a union

Each new event carries its question in the question field. If nobody can state the question, the event doesn't get added. The playbook chapter on creating a tracking plan explains the reasoning behind each rule, and Mixpanel's guide to events and properties describes the event-plus-property model the rules build on.

What should we track, and what should we ignore?

Track these

  • Sign-up, login and onboarding steps: one event per step type with a step property, not one per screen.
  • The first value moment for each product, with is_first_<thing> on the outcome event.
  • Core actions that create, change, use or export the product's value.
  • State changes such as a plan upgraded or a subscription paused.
  • Money: every payment, plan and credit outcome, sent from the server, with status.
  • Search and filters only where they're central, with char_count and result_count, never the query.
  • Server outcomes with no user present: scheduled jobs, background processing, webhooks. These are the events most often missed.

Ignore these

  • Hovers, scrolls, tooltips, collapsing panels, theme toggles and dismissed banners.
  • Pagination, and tab switches inside one screen unless the tabs are different features.
  • Screen views that carry no decision, and marketing-site navigation other than calls to action into sign-up.
  • Settings tweaks with no product consequence, and anything per keystroke.

The test: would a PM or analyst filter, break down or count by this in a report? Yes means track it. Maybe means skip it and raise a question: adding an event later costs one pull request, and removing one costs a migration.

How does the event budget work?

For each behaviour a change touches, the agent picks the first outcome that fits, in this order:

  1. No tracking change. Refactors, copy, styling, or anything that fails rule 1, with the reason in one line.
  2. Extend an existing event. A new way in gets a new entry_point value; a new variant gets a new enum value. This is the most common correct outcome for a UI change.
  3. Modify an existing event. Its firing moment, properties or values change, under the breaking-change protocol below.
  4. Deprecate an existing event. The surface or action is gone: status: deprecated, a deprecated_reason, and replaced_by if something replaces it.
  5. Add a new event. Only when none of the above fits.

More than 5 new events in one pull request (budget.new_events_per_pr in _conventions.yaml), or more than 2 for one new screen, needs a written reason for each event. Plans rot one reasonable-looking event at a time.

How does the Tracking Agent handle breaking changes?

Breaking an existing event is worse than missing a new one. A missing event costs a week of data; a silently changed one corrupts every dashboard built on it. So every item that changes the meaning of past data is labelled breaking and follows this protocol:

  1. Never rename in place. Add the new event and mark the old one deprecated with deprecated_reason and replaced_by. The old entry stays, because it explains the history in your analytics tool.
  2. Send both for one release for core events (sign-up, login, money, first-value events and anything on a dashboard), with dual_fire_until on the old entry, so reports can move without a gap.
  3. Log a changed firing moment with a changelog line starting SEMANTICS: and the date, so an analyst who sees a step change in a chart can find the cause.
  4. Give a changed type a new property name. Analytics tools can't retype history.
  5. Flag it in the report's breaking changes section, with the dashboards or funnels likely affected.

To find breaks, the agent walks a checklist for every event and user property a change can reach: firing moment moved, surface removed or merged, a new way into the same action, a new step in a flow, an enum value changed, a type or unit changed, a property's source changed, an error path changed, identity or account context changed, and a rename in code.

What data does the method never send?

Raw user text, prompts, search queries, file names, transcripts, emails or phone numbers as event properties, API secrets, and card or bank details. Send lengths (char_count), buckets (file_size_bucket) or IDs instead. datalyze validate flags property names that look like personal data, using pii_patterns in _conventions.yaml.

Questions about the tracking-plan method

Can we use our own event naming convention?

Yes. Set naming.event_pattern in _conventions.yaml, and namespaces if you prefix names with an area. The default is snake_case object_action, such as post_created and sign_up, with past tense not enforced.

Why not a separate event for failures?

Because every conversion rate then needs a union of two events, and funnels silently drop the failures. status and failure_reason on the outcome event keep both in one place.

Does the method change over time?

The four rules don't. The method is released in versions such as 2026.10.3, and you can pin one with licence.pin in .datalyze/config.yaml so results stay the same until you choose to move.

Where does this method come from?

From the tracking plans Datalyze builds and audits for clients. The problems the PR check is tested on are the ones we find most often in an analytics audit.