Tracking Agent docs

Tracking Agent concepts: registry, typed tracker and proposals

The registry is your tracking plan as YAML files in your repo, and every other Tracking Agent concept checks it, changes it or is generated from it. The typed tracker is generated from it, proposals change it through reviewed pull requests, and conventions, decisions, the baseline and statuses shape how it's judged.

By Ansh AgrawalUpdated

What is the registry?

The registry is your tracking plan, kept as YAML files in analytics/registry/. It's the source of truth: every change to it goes through a reviewed pull request, and the Google Sheet is only a view of it. Events are split into one file per area of the product, so teams rarely edit the same file.

text
analytics/registry/
  _conventions.yaml       the rules: naming, allowed values, budget, typed tracker, scan settings, reviewers
  _properties.yaml        shared event-property vocabulary and banned synonyms
  _user_properties.yaml   user (profile) properties
  _super_properties.yaml  properties sent on every event
  _groups.yaml            group or company properties (optional, B2B)
  _identity.yaml          when identify, alias and reset happen
  _baseline.json          problems accepted at install
  <area>.yaml             events for one area: account.yaml, posts.yaml, billing.yaml
analytics/generated/      the typed tracker (never edited by hand)
analytics/adapter/        the vendor adapter, the only code allowed to call the analytics SDK

The reference lists every field of an event and user property entry, and the playbook chapter on creating a tracking plan explains what a good entry answers.

What is the typed tracker?

The typed tracker is a module that datalyze generate writes from the registry into analytics/generated/. Your code calls it instead of the analytics SDK, so a wrong event name, a missing property or a value outside the plan is a compile error.

ts
import { track, serverTrack, user, serverUser } from '@/analytics/generated';

track.publishClicked({ entry_point: 'editor' });                // client events
serverTrack.postCreated(userId, { post_id, entry_point, status: 'success', failure_reason: null });
user.identify(userId);                                           // at sign-up and login
serverUser.setOnce(userId, { signup_date: new Date() });         // user properties set on the server
user.reset();                                                    // at logout

The vendor sits behind an adapter, so changing analytics tool means swapping one file. The generator writes TypeScript, Swift, Kotlin or Dart, and datalyze adapter <vendor> writes the adapter for Mixpanel, PostHog, Amplitude, Segment, RudderStack or GA4 in that language. In capture mode (DATALYZE_CAPTURE=1) the tracker records every call instead of sending it, which is what the generated tests check.

What is a tracking proposal?

A proposal is the agent's list of tracking changes for one pull request, saved as .datalyze/proposals/pr-<n>.yaml on the pull request's branch. Each item says what changes and why, the question it answers, the evidence (a file and line, or a query and its result), whether it's breaking, and how confident the agent is.

Reviewers edit each item's final copy and its note, which the agent treats as a binding instruction. Decisions come only from /datalyze comments, never from the file. See reviewing.

What are conventions and decisions?

Conventions are your house rules, in two files. analytics/registry/_conventions.yaml holds the rules a script enforces: the event-name pattern, allowed values, the new-event budget and the reviewers. .datalyze/conventions.md holds rules reviewers made in plain words while reviewing, which the agent treats as binding.

Decisions are the agent's memory of what you said no to. .datalyze/decisions.yaml records rejected items and skips, with reasons, so the agent doesn't propose the same thing again and the next audit can see every skip.

What is the baseline?

The baseline, _baseline.json, lists the problems accepted at install, so pull requests are judged only on what they add. When the Tracking Agent was installed on this site, the baseline accepted 41 legacy findings, mostly Title Case event names and placement used where the conventions say entry_point.

Regenerate it with datalyze baseline once clean-up pull requests have merged. It changes the rules for everyone, so make your analytics owner its code owner, along with _conventions.yaml and _properties.yaml.

What do the registry statuses mean?

StatusMeaningSet by
plannedIn the registry, not shipped yetThe PR check, on a branch
implementedThe call is in the code on the default branchThe workflow's after-merge job, after every merge to the default branch, in one pull request
needs_reviewAn open question blocks it, such as an unresolved rename or a disputed findingThe PR check, or datalyze audit --apply when nothing arrives
deprecatedThe surface or action is gone and the call removed; the entry is kept for historyThe PR check, with deprecated_reason and replaced_by

"Verified" is not a status. It's a column in the Google Sheet that a person fills in after seeing the data arrive with the right properties.

Questions about Tracking Agent concepts

Can we edit the registry by hand?

Yes, in a pull request like any other code. datalyze/rules validates it, and the PR check reviews it with the rest of the change.

Why is the typed tracker required?

It turns tracking mistakes into compile errors and gives the scanner one module to look for, whatever the vendor. Before it exists, the scanner reads your existing calls and wrappers, listed under scan.legacy_trackers in _conventions.yaml.

What happens to a deprecated event's entry?

It stays in the registry with deprecated_reason and replaced_by, because it explains the history in your analytics tool. The typed tracker drops it, so any call left behind fails to compile.

We're new to Mixpanel. Should we start with the Tracking Agent?

Start with a plan and working tracking, then add the check to keep it right. Our Mixpanel implementation service sets both up with you.