Best practices6 min read
Event naming
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, scroll, engagement, 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.
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 for the exact signature and what Mrkr records automatically for what's already tracked without any naming decision on your part.
For the full property-sanitization rules see 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.