# Event naming

> A naming convention for custom events that survives contact with a real team, and why it matters more here than in most tools.

Section: Best practices. Canonical page: https://mrkr.app/docs/best-practices/event-naming. Last updated: 2026-09-02.

A good event name describes what happened, not what happened to whom or when. Get this wrong early and every dashboard built on top of it inherits the mess.

## Object, then action

Name events `object_action`: `signup_completed`, `invite_sent`, `plan_upgraded`, `checkout_started`. Lowercase, snake_case, no spaces. This reads the same in the Events catalog, in a funnel step, and in a filter: you never have to remember whether you called it `SignupCompleted` in one place and `signup-complete` in another.

The tracker's own automatic events follow this rule for a reason: `pageview`, `outbound`, `download`, `page_leave`, `web_vital` are a small, fixed vocabulary. It never invents `outbound_hero_cta` or `outbound_pricing_partner`: the specifics live in properties, not the name. Do the same for your own events.

## Never put a variable value in the name

Every event name becomes a `dimension` in a daily counter (`rollups`, metric `event_count`). That counter is bounded per site per day: once too many distinct dimension values show up for one metric, the long tail folds into a single `_other` bucket so the table doesn't grow without limit. An event name is exactly the kind of thing that folds.

If you name events `plan_upgraded_pro`, `plan_upgraded_business`, `plan_upgraded_enterprise` instead of one `plan_upgraded` event with a `plan` property, you've manually created the long tail the folding mechanism exists to protect against. Once it folds, you can no longer tell how many of each happened, only that `_other` happened some number of times. The same applies to anything unbounded: a user id, an email, an order id, a timestamp baked into the name.

## Put the variable in a property instead

Every event carries up to 8 properties, each with a 64-character key and a 256-character value, enforced identically on the client and again on the server so a tampered payload can't smuggle more through. Keys are restricted to letters, numbers, `_`, `.`, `:` and `-`: anything else is silently dropped, not rejected, so a typo'd key just disappears rather than erroring your call.

> **Which 8 keys survive:** If you send more than 8 properties, the ones kept are the first 8 in *sorted key order*, not the order you wrote them. Pick a small, stable property set up front: a payload that varies which keys it includes from call to call can lose different properties on different events.

So `plan_upgraded` with `{ plan: "business", billing_period: "annual" }` is one bounded event name with two properties you can break a funnel or a chart down by, which is exactly what the three-name version couldn't offer without extra work.

## Good and bad

| Instead of | Problem | Do this |
| --- | --- | --- |
| `plan_upgraded_pro`, `plan_upgraded_business` | Value baked into the name; folds into `_other` once cardinality grows | `plan_upgraded` with `{ plan: "pro" }` |
| `click_button_hero_cta_v2` | Re-encodes the element into the event name, and drifts every time the button copy changes | Use `data-mrkr-event="cta_click"` with `data-mrkr-prop-*` and keep the detail in properties |
| `user_42981_purchased` | Unbounded value in the name; one row per user, forever | `purchase_completed` with the user identified by session, not the event name |
| `SignupComplete`, `signup-complete`, `signup_complete` | Three names for one thing, split across every report | Pick one: `signup_completed`, and use it everywhere |

## Where the name comes from matters too

If you're using the declarative `data-mrkr-event` attribute instead of calling `track()` directly, the name is whatever you put in the attribute, capped at 64 characters, the same limit `track()` enforces. See [the JavaScript API reference](https://mrkr.app/docs/reference/javascript-api) for the exact signature and [what mrkr records automatically](https://mrkr.app/docs/tracking/autocapture) for what's already tracked without any naming decision on your part.

For the full property-sanitization rules see [custom events](https://mrkr.app/docs/tracking/custom-events). Your own events are never billed (only pageviews are), so name them for clarity rather than for cost: see [what counts toward your quota](https://mrkr.app/docs/billing/what-counts-as-an-event).
