Product Analytics Tracking Plan: Define Events Before Development

Create a product analytics tracking plan with clear event triggers, properties, owners, retry rules, and QA cases. Follow a practical learning-app example.

Try Mockitt for Free
Practice request, session creation, and accepted answer shown as distinct events within one learning attempt

A product analytics tracking plan defines which events a product should record, exactly when they occur, and what information each event needs. Start with a product question, then specify triggers, properties, sources, owners, and validation cases. A list of button names is not enough: an attempted action and a successfully completed action can tell very different stories.

Include the agreed plan in the design handoff before development. Product, design, engineering, and analytics can then resolve ambiguous definitions while the flow is still easy to change.

This guide follows a fictional language-learning app. The team wants to understand where an attempt to start practice breaks down before the learner submits a first answer. Its event names, properties, and test cases are proposed specifications, not collected data or claims about an existing application.

Start with a question that the events can answer

“Track engagement” is too broad to guide implementation. The example team asks: “Of the recorded attempts to start practice, which reach a created session, and which reach an accepted first answer?” That question separates a learner’s intent from the service’s response and the learner’s next action.

Define the unit of analysis before choosing events. Here it is a start attempt, identified by an attempt_id. One learner can make several attempts. Reporting attempts as if they were distinct people would change the meaning of the result.

Agree the observation window and how late-arriving data will be handled before interpreting the funnel. An attempt made moments before a report runs has had less opportunity to reach an answer than one made earlier. Mark unfinished observation windows separately instead of immediately labelling those attempts failures.

Also state what the result cannot answer. An accepted answer shows participation in a practice activity; it does not establish learning, satisfaction, or retention. Those questions need their own definitions and evidence. Keeping this first question narrow avoids collecting every interaction merely because it is available.

Twilio Segment’s data-collection guidance connects tracking plans with business questions and consistent event naming. Use a stable name for the action, with changing details represented as properties. The vocabulary below is one proposed convention, not a requirement to use a particular analytics platform.

Write an event contract, not just an event name

For each event, specify the trigger, the component that can know it happened, and conditions that must not produce it. “Practice Started” is ambiguous: does it mean the learner tapped a button, the server created a session, or the first exercise became usable?

The proposed catalogue separates those meanings. A client event describes an interface occurrence; a server event describes an accepted operation. Assign one authoritative producer for each definition so two teams do not independently emit the same success event.

EventTrigger and producerDo not emit for
Practice Launcher ViewedClient renders the eligible launcher with an available start action; once per defined view instanceA hidden tab, loading placeholder, or an ineligible account
Practice Start RequestedClient accepts a valid start action and begins a new logical attemptA blocked action or a network retry of that same attempt
Practice Session CreatedServer commits a new practice session associated with the attemptA pending request or a replay that returns an existing session
Practice Start RejectedServer makes a terminal rejection for the attempt, with a defined reason codeA client timeout whose server outcome is still unknown
Practice Answer AcceptedServer accepts a new answer submission for the sessionA rejected answer payload or a replay of the same submission

The first accepted answer in a session can be derived from accepted submissions; the team does not also need a separately implemented “First Answer” event unless there is a clear reason. Specify how that derivation handles repeated submissions and arrival order.

The launcher event provides context but is not automatically the denominator for the start-attempt question. A missing client event might reflect collection failure or the product’s collection policy. It is not proof that a person never saw the screen. Preserve the distinction between unobserved behavior and behavior known not to have occurred.

Define properties with types, meanings, and limits

Segment’s Track specification distinguishes the event name from properties describing that action. Apply that separation to the example: a language choice should be a property, not a new event name for every language.

For each field, record its type, allowed values, which events require it, and who provides it. A property called status with undocumented values such as “done,” “ok,” and “complete” recreates the original ambiguity inside the data.

PropertyProposed rulePurpose
attempt_idOpaque string; required on request, creation, and rejection eventsConnect a logical start attempt with its result
session_idOpaque string; required after session creationAssociate accepted answers with the created session
submission_idOpaque string; required on accepted-answer eventsDistinguish a new answer submission from a replay
practice_modeString from the agreed set: review or new_materialCompare the two supported practice contexts
reason_codeRequired on rejection; controlled values such as content_unavailableExplain a known rejection without sending raw error text
schema_versionInteger; owned by the event-definition maintainerIdentify which property contract applies

Specify the relationship fields too. An answer’s session_id must refer to the session created for the attempt being analyzed. A session ID that changes after every screen refresh would prevent reliable joining, even if each individual event passes a type check.

Keep event timestamps and transport metadata in the implementation contract. Segment’s common-fields documentation, for example, distinguishes a message identifier from timestamps such as when an event occurred and when it was received. A transport message ID and the product’s attempt_id serve different purposes; do not assume one replaces the other.

Collect only properties needed for the stated analysis and approved collection policy. This example does not need answer text, learner names, email addresses, or free-form support messages. An opaque identifier still needs appropriate handling; calling it an ID does not make its use anonymous or unrestricted.

Decide how retries, failures, and missing events behave

Walk through a timeout before approving the plan. The learner starts practice, the server creates the session, but the response never reaches the device. A retry may retrieve the same session. Counting another creation would overstate success; counting a terminal failure at the first timeout would contradict the server’s actual outcome.

In this proposed design, a retry of the same logical operation keeps its attempt_id. A deliberately new start attempt gets a new ID. Engineering must define when the app offers each action and how the service handles repeats. The analytics specification should reflect that behavior rather than try to repair an undefined operation afterward.

Separate two forms of duplication. The collection pipeline may deliver the same event message more than once. The application may also emit two different messages for one business occurrence. Assign responsibility for both transport deduplication and business-event uniqueness. A pipeline’s message-level protection does not, by itself, settle whether two different messages describe one session creation.

Write the intended success condition into the functional specification: the session exists with an accepted identifier. Record the failure and unknown outcomes separately. A client can show a retry state without asserting that the server rejected the attempt.

Collection gaps also need a policy. Separate development traffic, agreed test accounts, invalid payloads, and unavailable collection from the analytical population. Document exclusions instead of quietly dropping records until a funnel looks plausible. Moving an event to the server does not remove the need to follow the product’s privacy and collection requirements.

Annotate the prototype where meanings diverge

Use a Mockitt interactive prototype to make the proposed states visible: practice launcher, starting, first exercise, and a retry state. Put event labels beside the action or result they describe. Treat the server-created event as a dependency annotation, not something that a successful screen transition proves.

Mockitt prototype example showing practice-start screens with separate request, session-created, and accepted-answer annotations
Example event annotations separate the learner’s action from the service’s confirmed result.

During review, follow one attempt across the screens. Selecting Start corresponds to the request event. The waiting state does not establish creation. The first exercise represents a successful response, while the server event is tied to the committed session. The first accepted answer is a later occurrence, even if the interface makes it easy to reach.

Then follow the timeout path. The annotation should say “outcome unknown; retry the same attempt,” rather than attach the rejection event to every error message. This is where an interface review can reveal a misleading analytics definition before code is written.

Keep the plan beside the prototype with event owners and unresolved questions. Mockitt supplies the visual reference for the discussion; the application and analytics systems must implement collection. Do not add tracking controls to the illustration or present a simulated flow as proof that events were sent.

Validate the contract, then maintain its meaning

Prepare test cases before implementation so QA can examine both the interface and the recorded events. The following are expected behaviors to verify, not results of tests performed for this article.

CaseExpected evidence
Normal start, then one accepted answerOne attempt links to one created session and one accepted submission.
Timeout after the server commits, then retryThe retry resolves the same attempt; no second business creation is counted.
Content unavailableA terminal rejection has an allowed reason; no session-created event belongs to that rejected attempt.
Replay of an accepted answerThe existing submission is recognized; it does not become a second accepted answer.
Client collection unavailableAny server-only records remain identifiable; the report does not infer a complete client funnel.

Validate required fields, types, allowed values, joins, and event timing. A valid payload can still be emitted at the wrong moment. Compare what actually happened in the test with both the event record and the implemented screen. Use design QA for visible behavior, while engineering and analytics verify collection and interpretation.

Finally, name the person who maintains each definition. If “session created” later includes a different kind of session, review the change with report owners before treating old and new data as comparable. Record effective versions and any migration rule. The tracking plan is useful only while the meaning of its events remains aligned with the product people are using.