Reserved events

The dollar-prefixed events the service acts on: pageview, pageleave, identify, alias, group, set and profile, with the exact shape of each.

Most event names mean nothing to the service: it stores them and reports on them. A small set of names beginning with $ are reserved: the service does something when it sees them, beyond writing a row. Send one by accident and you will change a profile or merge two people, so it is worth knowing the whole list.

The list

Everything else you send is your own event. $-prefixed names that are not in this table are stored like any other name, so a Mixpanel SDK's $app_open is just an event.

$pageview and $pageleave

{ "id": "…", "ts": "…", "event": "$pageview",
  "aid": "anon_9f2c41", "sid": "sess_51ab",
  "path": "/pricing", "url": "https://example.com/pricing",
  "ref": "https://news.example.com/" }

Page views are what sessions, bounce rate and time on page are built from. A single-page app must send one per route change: a history-based router fires no navigation the browser would tell us about.

$pageleave on unload closes the view. Without it, time on page for the last view of a session is unknown.

$identify

Merges an anonymous id into a person.

{ "id": "…", "ts": "…", "event": "$identify",
  "aid": "anon_9f2c41", "uid": "user_1024", "did": "user_1024" }

aid is the id being merged, uid the person it becomes. Both are required and must differ, or nothing happens. The merge rewrites the last 30 days of that anonymous id's events and sessions, folds its profile counters into the person's, and retires the anonymous profile. Full semantics: Identity and merge.

POST /v1/identify builds this event for you, and adds a $set when you pass traits.

$alias

{ "id": "…", "ts": "…", "event": "$alias",
  "aid": "ada@example.com", "uid": "user_1024", "did": "user_1024" }

Records the mapping only. No rewrite, no profile merge, free to repeat. Read aid here as "the new id" rather than "an anonymous id".

$group

{ "id": "…", "ts": "…", "event": "$group", "did": "user_1024",
  "props": { "$group_key": "company", "$group_id": "acme", "plan": "enterprise", "seats": 40 } }

The pair travels in props under $group_key and $group_id, because properties are the one container that survives validation unchanged from every client. Typed senders may use the top-level group: { key, id } field instead, which carries the same pair.

Any other property on a $group event is a trait of the group, not of the event: plan and seats above are recorded against acme. Traits merge across events, and the group's first-seen and last-seen move to cover them.

The person's other events in the same batch are stamped with the pair, so a report can group by company without a join. Events in later batches are not, until the next $group.

$set

{ "id": "…", "ts": "…", "event": "$set", "did": "user_1024",
  "props": { "plan": "pro", "email": "ada@example.com" } }

Every property merges into the person's profile. This is the event a Project token uses to write profile data, and the one Mixpanel's people.set maps to.

A $set is a profile write, not something the person did. Do not use it where an event belongs: $set with { "plan": "pro" } records that they are on Pro, while an Upgraded event records that they changed, and only the second one can go in a funnel.

The Mixpanel shim turns $set_once, $add, $union, $unset, $delete, $append and $remove into a $set carrying props.op with the original operation name. The operation is preserved so the intent is visible, but the arithmetic is not performed server-side: $add does not increment. Count in a report instead.

$profile

The trusted-only richer form. Needs a Server key; from any other writer the profile object is ignored.

{ "id": "…", "ts": "…", "event": "$profile", "did": "user_1024",
  "profile": { "email": "ada@example.com", "name": "Ada L", "plan": "pro",
               "subscriptionStatus": "active", "signedUpAt": "2026-02-01T00:00:00.000Z",
               "onboardedAt": "2026-02-02T09:12:00.000Z", "company": "Acme" } }

Known keys become profile columns; the rest are kept as extra profile properties. email is also hashed for lookup. Both signedUpAt and signed_up_at spellings are accepted.

Use $profile from a backend, where you have the authoritative record, and $set from a client, where you have whatever the person just typed.

Autocapture events

$autocapture (a click), $change (an input's value changed), $submit (a form was submitted) and $rageclick (repeated rapid clicks in one place) are written with element metadata in the event's el field: tag, a stable selector, visible text, href, id, classes and a form field name. Never an input's value.

They have no side effect on identity or profiles. They exist so a defined event can name an action retroactively from data you already collected.

Rules for your own names

  • 1 to 96 characters, from letters, digits, _ $ . : - and interior spaces. No leading or trailing space.
  • Names are case-sensitive and are not normalised. Signed Up, signed up and signed_up are three events.
  • Avoid inventing new $ names. They will be stored, but the prefix reads as "the service did this", and a future reserved name could collide with yours.
  • Name after what happened in your product's language. subscription_started outlives three redesigns; blue_button_clicked does not.

Next