Plan format
A tracking plan is a YAML file that catalogues every event your product emits. Leatsmap reads it for three purposes:
- The collector validates incoming events against per-event JSON Schemas.
- The codegen tool emits typed
track()overloads for the SDK. - The plan-diff tool fails CI on breaking changes between versions of the plan.
Top-level shape
Section titled “Top-level shape”version: 1 # plan format version — only `1` is valid in v1.0events: <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.
Classifications
Section titled “Classifications”| Classification | Examples |
|---|---|
behavioral | page_view, link_clicked, scroll_depth |
revenue | checkout_completed, subscription_renewed |
system | api_error, feature_flag_evaluated |
identification | user_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 JSON Schema
Section titled “Props is JSON Schema”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.
Worked example
Section titled “Worked example”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: stringWhere the file lives
Section titled “Where the file lives”By convention the plan lives at:
shared/tracking-plan/schema.yamlYou 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.
Next steps
Section titled “Next steps”- Validation — what the collector does when an event does not match the plan.
- CI breaking-change detection — fail PRs that remove an event or tighten a constraint.
- TypeScript codegen — generate typed
track()overloads from the plan.