# Players and properties (/docs/getting-started/identify)

In a Roblox game every player is already signed in, so there's nothing to identify. The module uses the player's **UserId** (as a string, `"123456789"`) as their distinct id. Every session, on every device, belongs to the same person in RoChart.

Server events (`$server_heartbeat`, `$server_shutdown` and anything sent with `trackServer`) use `"$server:" .. game.JobId` instead. They never create a person, so servers don't show up as players.

## Properties set for you [#properties-set-for-you]

On every `$session_start` the module updates the player's profile:

| Property | Value |
| --- | --- |
| `name`, `display_name` | Username and display name |
| `account_age_days` | Roblox account age in days |
| `premium` | Whether they have Roblox Premium |
| `locale` | `player.LocaleId`, such as `en-us` |
| `country` | ISO country code from `LocalizationService` |
| `platform` | `Computer`, `Phone`, `Tablet`, `Console`, `VR` or `Unknown` |

Set once, on the first session RoChart sees, and never overwritten: `first_platform`, `first_join_source` and `first_campaign`.

Roblox doesn't share age or gender with games, so RoChart has neither.

## Your own properties [#your-own-properties]

Put what describes the player on the player: level, class, VIP status, how many Robux they've spent in your game.

```luau
RoChart.setUserProperties(player, { level = 12, class = "mage", vip = true })
```

Filters and breakdowns on a person property use the player's **current** value. If someone reached level 20 today, all their past events count as level 20. To analyse "what level were they when they did this", also put `level` on the event:

```luau
RoChart.track(player, "boss_defeated", { boss = "kraken", level = 12 })
```

## Events from outside the game [#events-from-outside-the-game]

A website, Discord bot or backend can send events for the same player. Use the UserId as a string as the distinct id:

```ts title="discord bot (Node)"
rochart.capture({ distinctId: String(robloxUserId), event: 'discord_linked', properties: { guild: 'main' } })
```

If your website knows the visitor's Roblox UserId, call `rochart.identify(String(userId))` there. Their visits before that point are then linked to the player too.

<Callout type="info" title="Two players are never merged">
  RoChart never combines two people who both have an id. It also ignores placeholder ids such as `"undefined"`, `"null"`, `"anonymous"` and `"0"`.
</Callout>

## Groups: clans, guilds, parties [#groups-clans-guilds-parties]

Groups let you count and analyse something bigger than one player, such as clans. Attach an event to a group with the `$groups` property:

```luau
RoChart.track(player, "clan_war_won", { ["$groups"] = { clan = clanId } })
```

Group properties (name, member count) are set from the [Node SDK](/docs/reference/sdk#node--bun) with `groupIdentify` or over HTTP with `$groupidentify`. Each group type gets its own page under **People**. See [Groups](/docs/people/groups).

<Callout type="warn" title="Up to five group types per project">
  One or two group types (`clan`, maybe `party`) is usually enough. Once five exist, a sixth type isn't tracked.
</Callout>

## Check that it works [#check-that-it-works]

Open **People → Persons** and search for your username or UserId. Your profile shows the properties above, and its timeline lists your sessions and events.
