Sign in
Colour theme

The analytics.yaml manifest

One file in your repository declares every event the product may send. It is reviewed like any other code, and everything else is derived from it.

The file

version: 1
project: liinks

events:
  page_published:
    description: User published their page
    tags: [activation]
    props:
      template:
        type: string
        enum: [minimal, grid, stacked]
      link_count:
        type: number

  subscription_started:
    revenue: true
    tags: [conversion]

Fields

  • version — the manifest schema version. Currently 1.
  • project — the project's domain, which events are written under. Matches data-site in the tracker snippet and site in the API, exactly as the dashboard shows it.
  • events — a map of event name to declaration. Names starting with $ are reserved.
  • description — what the event means, for the people reviewing the diff and for the generated SDK's doc comments.
  • tags — free-form labels; activation and conversion are the conventional ones.
  • props — a map of property name to { type, enum? }. Types are string, number and boolean.
  • revenue: true — marks an event as carrying money. Revenue events can only be sent from the server SDK; the browser path ignores the field.

Never put personal data in props: no emails, names, addresses or user-authored text. Props are for the shape of an action, not for who took it.

What is generated

npx analytiics codegen    # writes analytics.gen.ts
npx analytiics validate   # checks the manifest, with errors addressed to a human

The generated module gives you one typed function per event:

import { track } from "@/analytics.gen";

track.pagePublished({ template: "grid", link_count: 12 });

// Type error: "carousel" is not assignable to "minimal" | "grid" | "stacked"
track.pagePublished({ template: "carousel" });

// Type error: unknown event. Add it to the manifest first — that is the point.
track.pageShared({});

So a renamed event breaks the build rather than the dashboard, and a typo in an enum value never reaches production.

What your dashboard does with it

Push the manifest — analytiics codegen does it, or analytiics push on its own — and the sections appear. Nothing is configured, and nothing can be: the rules are fixed, and the way to change what you see is to change the file.

  • Every event gets a card, with its description, its count over the window and its trend. An event you have declared but never sent reads zero rather than going missing, because an empty chart is a true statement about your code and an absent one looks like an unpopular feature.
  • `enum` props become ranked breakdowns under the event they belong to. A number cannot be an enum, so link_count gets no card — it was never going to be a list of values.
  • `tags` become sections. An event carrying several is placed under the first and shows the rest, so one chart is never drawn twice on one page.
  • `dashboards.funnels` become funnels, counting people rather than events and following them across the browser/server boundary: a funnel ending in a server-side purchase still finds the visit that started it.
  • Events you send but never declared are listed on their own, with counts. That gap is the whole reason a tracking plan exists, so the dashboard names it rather than hiding it.

The sections are off for anyone but you until you publish them, unlike the web analytics cards. Your event names describe the inside of your product, and the count of subscription_started is your revenue figure with the currency taken off. Turn them on per project in settings.

Keeping it honest in CI

A file is only the source of truth if something notices when the code stops agreeing with it. That is analytiics check: it reads the manifest, finds every call site in the repository, and reports where the two have drifted — an event sent but never declared, an event declared but never sent, a property that has quietly changed shape, a generated module left behind by a manifest that moved on.

It warns and exits zero unless you pass --strict, so adopting it can never be the reason a release is blocked. See the CLI reference for the command and a pull-request workflow to copy.

Last updated 2026-08-27. This page is also available as Markdown at /docs/manifest.md, or from this URL with Accept: text/markdown.