> For the complete documentation index, see [llms.txt](https://docs.millimetric.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.millimetric.ai/reference/event-naming.md).

# Event & property naming

There's no schema enforcement on event or property names — Millimetric will store whatever you send. But analytics taxonomies rot fast unless you have a convention. Here's ours.

## Event names

**snake\_case, past tense, scoped to the actor.**

```
✅  signup
✅  trial_started
✅  checkout_completed
✅  invite_sent
✅  agent_task_completed

❌  Sign Up
❌  signing-up
❌  signupCompleted
❌  Signup Successful
```

### `$`-prefix is reserved

System events emitted by the SDK or the server start with `$`. Don't define your own `$`-events; they're indistinguishable from system ones in the dashboard.

\| `$pageview` | Browser SDK on load and SPA navigation. | | `$identify` | Server, on `POST /v1/identify`. |

### Verb in the past tense

`signup` is fine, but `signed_up` is *better*. Past tense reads naturally in funnel queries: "users who **signed\_up** then **subscribed**".

That said, the existing convention in this codebase uses bare nouns/short verbs (`signup`, `purchase`, `clicked_pricing`) — both work. Pick one and stick to it.

### Don't pack multiple events into a name

```
❌  button_clicked_pricing_page_hero
❌  user_logged_in_via_google_oauth

✅  clicked_cta             (with properties: { page: "pricing", section: "hero" })
✅  logged_in               (with properties: { method: "google" })
```

Property cardinality is cheap. Event-name cardinality is what kills your dashboards.

### Roughly 30–50 events is plenty

If you have 200 distinct event names, you almost certainly should have fewer events with more properties.

## Property names

**snake\_case. Type the value. Include units where ambiguous.**

```
✅  amount_cents: 4900
✅  currency: "usd"
✅  duration_ms: 1240
✅  is_first_purchase: true
✅  user_role: "admin"

❌  Amount: "$49.00"
❌  duration: 1.24
❌  firstPurchase: "yes"
❌  Role: "Admin"
```

### Booleans named as questions

`is_paid`, `has_premium`, `was_invited`, `did_complete_onboarding`. Reads nicely in `WHERE` clauses.

### Units on numbers, always

`duration_ms`, `amount_cents`, `latency_ms`, `size_bytes`, `weight_kg`. Pick a unit per metric and never mix.

### Money in cents

Or any fixed-precision integer. **Never floats** for revenue. `amount_cents: 4900`, plus `currency: "usd"`. Always together.

### `$`-prefix on properties means "ambient context"

The browser SDK adds `$viewport_w`, `$viewport_h`, `$language`, `$timezone`. Following that convention for your own ambient context (`$session_user_role`, `$build_version`) keeps event-specific properties visually distinct from cross-cutting ones.

## Conventions tools rely on

If you set these with the listed names, dashboards and MCP tools will Just Work.

| Property                                                              | Used for                               |
| --------------------------------------------------------------------- | -------------------------------------- |
| `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term` | Classifier (also reads them off `url`) |
| `fbclid`, `gclid`, `ttclid`, `msclkid`, `li_fat_id`                   | Classifier                             |
| `amount_cents` + `currency`                                           | Revenue dashboards (roadmap)           |
| `experiment_id` + `variant`                                           | A/B test analysis (roadmap)            |
| `plan` (string)                                                       | Cohort filtering on user-tier          |
| `path` (on the event itself, not in properties)                       | Top-paths breakdown                    |

## A small starter taxonomy

Steal this for a SaaS product:

| Event                   | When                    | Key properties                                       |
| ----------------------- | ----------------------- | ---------------------------------------------------- |
| `$pageview`             | every navigation        | `path`, `url`, `referrer` (auto-captured)            |
| `signup`                | account created         | `plan`, `referral_code`, `invited`                   |
| `trial_started`         | trial begins            | `plan`, `trial_days`                                 |
| `subscription_started`  | first paid charge       | `plan`, `amount_cents`, `currency`, `billing_period` |
| `subscription_changed`  | upgrade/downgrade       | `from_plan`, `to_plan`, `amount_cents`, `currency`   |
| `feature_used`          | a notable in-app action | `feature`, `result`                                  |
| `invite_sent`           | user invites a teammate | `count`                                              |
| `support_ticket_opened` | help requested          | `category`, `priority`                               |
| `error_shown`           | user-facing error       | `error_code`, `http_status`                          |
| `account_deleted`       | farewell                | `reason`                                             |

For e-commerce, swap `signup`/`trial_*`/`subscription_*` for `viewed_product`, `added_to_cart`, `removed_from_cart`, `started_checkout`, `completed_checkout`, `refunded`. See the [E-commerce recipe](/recipes/ecommerce.md).

## Renaming is a chore — pick now

There's no rename API. Renames happen by:

1. Start emitting the new name.
2. Wait for the retention window to pass (default 90 days).
3. Old events expire, new events have the new name.

Or query both names with a `CASE WHEN` until the old one rolls off. Easiest by far is to pick a convention before you start and write it down somewhere your team will read it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.millimetric.ai/reference/event-naming.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
