analytics
why
analytics is the product's memory of what visitors actually did; its value exists only when each fact is attributable to a question someone reads. the invariant is signal density: every event answers a named question in domain vocabulary and has an owner. unowned interaction tracking buries answerable signals in noise, trains the team to ignore dashboards, and leaves product decisions running on intuition. a small question-driven event set keeps evidence cheap to collect and direct to act on.
rule
an analytics event is a structured, durable fact about product use — the same discipline as structured logging for the internal product. every event answers a named product question, uses domain glossary vocabulary, and has an owner who reads the answer.
an event without an answerable question is noise: decisions run on incomplete data, success/failure gets attributed to the wrong signals, and unread events pile up and train the team to ignore analytics. metrics without questions are waste disguised as instrumentation.
event design
| property | standard |
|---|---|
| name | stable domain phrase: onboarding.fvm.reached, run.started. |
| fields | glossary nouns with typed values (workflowId, surface, outcome). |
| question | the named question it answers, recorded where events are declared. |
| identity | correlation id when the event spans an operation. |
| privacy | no secret payloads, no unclassified content, per privacy and content ownership. |
instrument at the boundary that owns the fact — the route, the workflow boundary, the mutation — not sprinkled through components.
the question set
design the event set from the product questions, written down:
| question | events |
|---|---|
| do visitors reach the first valuable moment? | arrival, each onboarding step, FVM reached. |
| where do they abandon? | step exits with the step name. |
| which capabilities are used? | operation-level invoked events. |
| do workflows succeed for people? | workflow started/completed/failed (already in metrics and alerts). |
| do changes help? | the before/after of the question the change addressed. |
do not
- instrument everything instrumentable; instrument the question set.
- send PII or unclassified content in event payloads.
- track third-party script events with different names for the same fact.
- keep an event whose question nobody can state.
- ship a change without recording which question it moves, when it has one.
verification
list the question set and its events. every declared event maps to a question; every question's dashboard/answer can be read today. fire each event once through its owning boundary in a non-production environment and confirm name, fields, and vocabulary match the declaration.
good and bad
bad
track("button_clicked", { color: "blue", page: location.pathname });track("input_focused", { fieldName: "email" });track("form_submitted", { page: location.pathname, timestamp: now() });
these events track every interaction without naming what they answer. when
form_submitted counts rise, there is no baseline question: engagement up?
repeated submission retries? completions up or just attempts? the event becomes
noise; the team stops reading dashboards and decides on intuition.
good
// question: do visitors reach the first valuable moment?track("workflow.started", { workflowId, surface: WorkflowSurfaceEnum.Editor });// question: where do users abandon?track("workflow.setup_skipped", { connectionRequired: true });// question: do workflows succeed for people?track("workflow.completed", { workflowId, durationSeconds, itemCount });
each event names its question, uses domain vocabulary, and has a declared owner (the product lead managing onboarding or success metrics) who reads the dashboard. the team tracks "completion rate" not just "form_submitted", so metric attribution is direct and actionable.