Track

Events and people

Naming events, properties, identifying users, sessions, and the limits that apply.

Everything in AnyAnalytics is an event: a name, some properties, who did it and when. Pageviews, level completions and purchases all go through the same pipe, so every report works with every event. This page covers how to name them, what they can carry, and how events become people and sessions.

Naming events

Pick names that say what happened, in the past tense, in snake_case: signup_completed, level_completed, item_purchased. A few habits keep reports tidy:

  • Keep the name generic and put the details in properties. Send level_completed with { level: 3 }, not level_3_completed.
  • Names are case-sensitive and compared exactly. Signup and signup are two different events.
  • Names can be up to 200 characters. Leading and trailing spaces are trimmed.
  • Don't start your own event names with $. That prefix is used by the events the SDKs send for you.

Properties

Properties are a JSON object: strings, numbers, booleans, null, arrays and nested objects all work. Values that can't be turned into JSON (functions, for example) make the SDK drop the event and log why.

track.jsjs
analytics.track("level_completed", {
  level: 5,
  duration: 82,
  score: 1200,
  difficulty: "hard",
  power_ups: ["shield", "magnet"],
});

Use the same property name and type for the same idea across events (level is always a number, plan is always a string). Breakdowns and filters then line up across your whole project.

Heads up

Don't put secrets or personal data you don't need into properties. They're stored as you send them.

Reserved property names

PropertyMeaning
revenueA number (or numeric string) counted as money. See Revenue.
currencyISO code of the revenue, such as USD or EUR.
$setPerson properties to set, overwriting earlier values.
$set_oncePerson properties to set only if they were never set.

Events sent for you

The SDKs and the script tag send a few events with a $ prefix. They power the built-in reports, and the busy ones are kept out of "Top events" lists.

EventSent whenKey properties
$pageviewA page loads or a single-page app navigates (script tag, or the SDK with pageviews on)$url, $pathname, $title, $referrer, $referring_domain, utm_*
$screenYou call screen("Shop") in an app or game$screen_name
$outbound_clickA visitor clicks a link to another site (script tag)$outbound_url, $outbound_domain
$session_startThe first event of a new sessionNone
$identifyYou call identify()$anon_distinct_id, $set
$exceptionYour app or game reports an error (the engine and mobile SDKs can catch them for you)See Game events
$payment, $refundYour Stripe integration records a payment or refundrevenue or refund, currency

People and identify()

Each device gets a random anonymous id the first time it runs your code. Every event carries it, so you get a full picture of a visitor or player before they ever sign in. When they do, call identify() with your own user id:

auth.jsjs
// After sign-in: everything this device sent before is merged into user_123
analytics.identify("user_123", { plan: "pro", email: "[email protected]" });

// On sign-out: forget the user, start a new anonymous id and session
analytics.reset();
  • From then on, events are sent under your user id. The device's anonymous id is linked to it, so the person's earlier anonymous events count as theirs too.
  • The same user signing in on a phone and a laptop becomes one person with both devices' history.
  • An anonymous id belongs to the first user it was linked to. Call reset() on sign-out so the next person on a shared device starts fresh.
  • Use a stable id that never changes, such as your database id, rather than an email address. Ids can be up to 200 characters.

Person properties

Traits passed to identify() become the person's properties, shown on their profile in Persons. You can also attach $set and $set_once to any event. Properties set while someone was still anonymous follow them once they're identified.

billing.jsjs
// Person properties can ride on any event
analytics.track("plan_changed", {
  plan: "team",
  $set: { plan: "team" },             // overwrites the latest value
  $set_once: { first_plan: "free" },  // keeps the first value ever sent
});

Sessions

A session is a run of activity from one device. The SDKs start a new one after 30 minutes without any event, send a $session_start, and tag every event with the session's id. Each SDK lets you change that timeout. Session length is the time between a session's first and last event.

Server code has no device to remember a session on. With the JavaScript SDK on a server, use capture() and pass a sessionId yourself if you want events grouped; see the JavaScript SDK.

Context: platform, version and device

Alongside properties, each event carries a context describing where it came from. The SDKs fill in what they can detect; you can add the rest.

FieldExample
platformweb, ios, android, windows, node…
app_version1.4.2
app_build212
os, os_versionAndroid, 15
devicePixel 9
browser, browser_version, device_typeChrome, 129, mobile
locale, timezoneen-US, Europe/Paris
country, region, cityTwo-letter country code (US); usually left to us
analytics.jsjs
analytics.init({
  writeKey: "vxw_YOUR_WRITE_KEY",
  host: "https://…",
  context: { platform: "windows", app_version: "1.4.2", app_build: "212" },
});

// Later, once you know more
analytics.setContext({ device: "Steam Deck" });

Platform names are lowercased, so Windows and windows count as one. For web traffic, browser, operating system and device type are read from the browser when you don't send them. Location comes from the visitor's IP address unless you send a country yourself. Events from server code (platform node or server) get no location from the request, since a server's address says nothing about your user.

Timestamps and late events

Each event records when it happened, not when it arrived. Games played offline can send events hours or days later and they still land at the right time.

  • Device clocks are often wrong. The SDKs send their clock time with each batch, and event times are shifted by the difference to ours.
  • Events more than 60 days old are rejected.
  • Events more than 60 minutes in the future are recorded at the time they arrived.
  • The SDKs give every event a unique id. If a batch is sent twice (after a network error, say), the copies are recognized and counted once.

Limits

WhatLimit
Event name200 characters
User or anonymous id200 characters
Properties of one event32 KB as JSON
Context of one event8 KB as JSON
Events per request500
Request size1 MB

Each event is checked on its own: one invalid event is rejected with the reason, and the rest of the batch is still stored. The SDKs batch and retry for you; if you send events yourself, see the HTTP API.

What gets filtered out

  • Search engine crawlers, link previews, uptime monitors and AI crawlers, whatever they send.
  • Automated browsers. The script tag doesn't even start in them.
  • Command-line and script HTTP clients claiming to be a web browser (platform web), and "browsers" with no user agent at all. The same clients are fine for server and game-engine events.
  • Known referrer-spam domains.
  • Your own traffic, if you set it up. See Excluding your own traffic.

Checking your events

Open Live events in your project. It shows every event as it arrives, marked accepted, duplicate or rejected, and rejected events come with the reason. Turn on your SDK's debug option (or data-debug on the script tag) to see what's being sent from the browser or app console.