Skip to content

Plan format

A tracking plan is a YAML file that catalogues every event your product emits. Leatsmap reads it for three purposes:

  1. The collector validates incoming events against per-event JSON Schemas.
  2. The codegen tool emits typed track() overloads for the SDK.
  3. The plan-diff tool fails CI on breaking changes between versions of the plan.
version: 1 # plan format version — only `1` is valid in v1.0
events:
<event_name>:
description: <string> # required
owner: <string> # required, free-form (team or person)
classification: <enum> # behavioral | revenue | system | identification
props: # required, JSON Schema (Draft 2020-12)
type: object

Event names match ^[a-z0-9_]+$ — snake_case so generated TypeScript identifiers are ergonomic and the URL/SQL surface is predictable.

ClassificationExamples
behavioralpage_view, link_clicked, scroll_depth
revenuecheckout_completed, subscription_renewed
systemapi_error, feature_flag_evaluated
identificationuser_signed_up, user_signed_in, merge

Classifications are metadata only in v1.0 — the platform does not branch on them. They become first-class in v1.1 when retention / cohort models pick a default “qualifying event” by classification.

props is a JSON Schema (Draft 2020-12) object. The collector enforces it at ingest. Keep additionalProperties: false unless you genuinely need a free-form payload — extra keys silently flowing through the pipeline are the #1 source of analytics drift.

version: 1
events:
page_view:
description: Page navigation tracked automatically by the SDK on init and on history-API navigations.
owner: data-platform
classification: behavioral
props:
type: object
required: [url]
additionalProperties: false
properties:
url:
type: string
format: uri
referrer:
type: string
title:
type: string
checkout_completed:
description: User finished checkout and a payment intent succeeded.
owner: ecommerce
classification: revenue
props:
type: object
required: [order_id, total_cents, currency]
additionalProperties: false
properties:
order_id:
type: string
minLength: 1
total_cents:
type: integer
minimum: 0
currency:
type: string
pattern: "^[A-Z]{3}$"
coupon_code:
type: string

By convention the plan lives at:

shared/tracking-plan/schema.yaml

You can move it; tooling/codegen accepts a --plan path override. Hosted leatmap users don’t configure the collector directly — the path is inferred from your tracking-plan upload in the dashboard.