Where we start
Product analytics is often sold as dashboards. It is really a writing discipline. Somebody decides, usually in a sprint and usually in a hurry, which moments of a user's life inside the product get written down, what each one is called, and which details travel with it. Every later question, from "is activation up?" to "did the AI feature help?", can only be answered from what was written. The six leader sessions work up from that diary to the product review; the eight analyst sessions build the same things in Python on real public data.
★ What you walk out with tonight. A one-page tracking plan for the five moments your product most needs to know about, written in Object Action names with the properties each one must carry, and the one question that stops most analytics arguments before they start: "which event, exactly, and who decided what it means?"
One entry in the diary
5 min liveGitHub publishes its public activity as a stream of events, and GH Archive keeps every hour of it as a file anyone can download. In the hour starting 15:00 UTC on 4 March 2024 there are 279,130 of them. Pick any one. It has the same five parts as an event in any product, whether it records a push to a repository, a song played or an invoice sent.
LiveActor, action, object, time, properties3 min▶
Actor is who did it. In GitHub's diary it is an account with a numeric id and a login; the login can be renamed, the id cannot. In the one hour we opened, 7 accounts appear under more than one login. Anything that counts people must count the id.
Action and object are the verb and the noun. GitHub folds them into one type (PushEvent, WatchEvent, CreateEvent) plus a detail in the payload: a CreateEvent can create a branch, a tag or a whole repository, and only the payload says which. That is the first product-analytics trap you will meet: one name hiding three different moments.
Time is a UTC timestamp. Properties are everything else that travels with the event: how many commits a push carried, which branch a pull request targets. Properties are where the useful questions live, and they are also what gets forgotten when an event is added in a hurry.
Self-studyWhy an event and not a table of users2 min▶
A users table says what is true now: plan, country, signup date. An event stream says what happened, in order. Every product metric that involves time, activation, engagement, adoption, retention, is a question about the order of things, so it can only be answered from events. The users table is still needed, to say who a person is; the events say what they did. Session 2 of the analyst track loads a real hour of the stream and shows how different it looks from a table: most actors appear once, a few appear thousands of times.
Renamed, and counted twice. A product team counts weekly active users by username because it is readable in the export. A user renames their account on Wednesday and becomes two users that week, one who went quiet and one who arrived. At the scale of one GitHub hour that is 7 accounts; across a month of a large product it is a measurable slice of "new" users who are nobody new. The fix is one decision, written once: people are counted by an id that never changes.
The name decides what can be counted
6 min liveAn event nobody can find is an event nobody counts. The convention most analytics teams settle on is Segment's Object Action framework: choose the objects first, then the actions a customer can take on them, so the diary reads "Repository Created", "Code Pushed", "Issue Opened". The list of those names, with the properties each must carry and who owns it, is the tracking plan.
LiveObject Action, and the three rules that come with it3 min▶
Segment's guidance, which most tools and teams have converged on, is to pick objects first (Product, Application, Repository) and then the actions a customer performs on them (Viewed, Installed, Created), so that an event reads "Product Viewed". Their house style is Proper Case for event names and snake_case for properties, and they are explicit that the style matters less than the consistency: "The only thing that really matters is that you keep it consistent!"
Three rules follow. Past tense, because an event records something that happened. No variables in the name: "Plan Upgraded" with a property plan = "pro", never "Upgraded To Pro", or every new plan becomes a new event nobody remembers to add to the chart. One moment, one name: if two names might mean the same thing, one of them is a bug.
LiveWhat a tracking plan is for2 min▶
A tracking plan is a table: event name, the moment that triggers it, the properties it must carry with their types, and an owner. It looks like documentation and works like a contract. Engineers implement against it, analysts query against it, and a validator can check the live stream against it. Run against the real hour, the five-line plan above finds zero type violations, and still catches 234 "Code Pushed" events with commits = 0: valid by type, wrong by meaning. That is the kind of thing only a written plan lets you notice, because only a written plan says what a push is supposed to mean.
Self-studyOne name hiding three moments2 min▶
GitHub's own CreateEvent is the cautionary example. In the hour we opened, 39,497 CreateEvents are split 27,168 branches, 10,384 repositories and 1,945 tags. A chart titled "Creates per hour" would be 69 percent branches and read as if it counted new projects. The payload knows the difference; the name does not. When you inherit a diary, the first job is to find the names that hide more than one moment and split them in the plan.
The pages that were never written
4 min liveA diary is also defined by its blank pages. GitHub's public stream never records an account being created, never records anything in a private repository, and never records a person reading code without touching it. Every product's diary has blanks like these, and the dangerous ones are the blanks nobody wrote down.
LiveFirst seen is not new2 min▶
The tempting shortcut, when a data source has no signup event, is to call the first time an account appears in your window its start. On GitHub that is almost always wrong: most accounts active in any given hour have existed for years and were simply quiet before the window opened. A "new users" chart built that way counts people who took a holiday.
What the public diary does record is the birth of a repository: a CreateEvent whose payload says repository happens exactly once, at the moment it is created. In our hour, 10,384 public repositories were born. That is why the activation bench in analyst session 8 treats a new repository the way a SaaS product treats a new workspace, and why it says so on the widget.
Self-studyWrite the blanks into the plan2 min▶
Every tracking plan should carry a short section called "what we do not see": logged-out browsing, activity inside an integration, offline use, consent opt-outs, anything behind an ad blocker. It costs five lines and it prevents the most common executive misreading, which is treating the absence of an event as the absence of the behaviour. A product review that asks "is this a real drop, or a drop in what we can see?" is only possible if someone wrote the blanks down.
Your first tracking plan, on one page
★ 22 min · everyone buildsNo tools and no data access. A blank sheet, your product, and five decisions per row. This is the artifact every later leader session leans on: session 2 picks your activation candidate from it, session 4 adds the features you want adopted, session 5 adds the AI feature.
List the five moments your product most needs to know about. Not the five easiest to track. Start from the decisions your team makes every quarter: whether onboarding works, whether a feature is used, whether people come back. Each decision needs at least one moment, and one of the five should be the birth of the thing your product is organised around: an account, a workspace, a project.
Name each one Object Action, past tense, Proper Case. Choose the objects first, then the verbs. If a name needs a variable in it, move the variable into a property.
Write the trigger precisely. "When the user creates a workspace" is not a trigger. "When the first workspace is saved, server side, fired once" is. The difference is whether a double click, a retry or a page reload fires it twice, and that difference decides whether the count is true.
Give each event two to four properties, with types, and an owner. An id for the object, an id for the actor, and the one or two details a question will need. The owner is the person who says what it means when two dashboards disagree.
Write the blank-pages tab. Five lines on what the plan cannot see, and why. Logged-out use, activity inside partner integrations, users who declined tracking. Put the date on the page. You will come back to it in session 6.
Later never comes cheaper. An event that shipped with the wrong name has history under that name. Renaming it splits the chart at the rename date or needs a mapping forever. Twenty minutes on the plan before the sprint is the cheapest analytics work there is.
Before session 2
30 min- Find your product's current event list, in whatever tool holds it, and count the names. Mark the ones that break a rule: present tense, a variable in the name, two names for one moment.
- Find one name hiding several moments, the way GitHub's CreateEvent hides branches, tags and repositories. Write down what share of that event is each moment, or who could tell you.
- Check how people are counted. Ask the analyst which field defines a user in the weekly active chart. If the answer is an email or a username, you have found a renaming problem.
- Bring the one-page plan. Session 2 asks which of its five moments predicts that someone stays, and the answer is usually not the one you would guess.
Three questions
Clear all three and leader session 1 gets stamped in your passport.
1 · In one real GitHub hour, 7 accounts appear under more than one login. What does that mean for a weekly active users chart?
A login is a label; an id is an identity. Renames are ordinary behaviour, and a count keyed on the label quietly inflates both "churned" and "new". The decision belongs in the tracking plan, written once.
2 · Which event name follows Object Action and the no-variables rule?
Object first, past-tense action second, and the thing that varies travels as a property. "UpgradedToPro" becomes a new event for every new plan, and nobody remembers to add it to the chart.
3 · GitHub's public stream has no signup event. Why does the activation bench count new repositories rather than accounts first seen in a window?
A cohort has to start at a moment the diary actually records. When the birth you care about is a blank page, pick a birth that is written down and say plainly what it stands for.
What this session teaches, and where it came from
Every fact on this page, and its verification tier, is recorded in the course's source map.
Leader session 1 cheat sheet · pin this
Your plan has five moments. Which one predicts that someone stays? Facebook's growth team is reported to have answered "7 friends in 10 days" and Slack's founder said "2,000 messages". Session 2 traces both to the earliest source that can be read, shows what each one can and cannot prove, and puts eight candidate definitions side by side on 8,348 real new repositories. Bring your plan.