Users & presence
A user is an account that has joined a server. Presence is whether that user is connected right now, plus their status and the apps and devices they’re using. This page explains how the server tracks both and who gets to see what.
{ "username": "mist", "nickname": "Mist", "roles": ["admin", "user"], "color": "#FF0000", "cracked": false, "status": { "status": "online", "text": "Shipping docs" }, "clients": ["originchats"], "devices": ["computer"]}Commands and events identify users by username. Two flags classify an account:
cracked: truemarks a local account created on this server rather than a Rotur account. See server accounts.bot: truemarks an account that declared itself a bot. The field is left out for other accounts.
Neither flag grants or removes any permission. See the user schema for every field, and users_list and users_online to load them.
Connections and membership
Section titled “Connections and membership”One user can have several WebSocket connections open at once, for example a desktop app and a phone. The server groups them by account.
| Event | When it’s sent |
|---|---|
user_join |
An account joins the server for the first time, or rejoins after leaving. |
user_connect |
The user’s first connection opens. |
user_disconnect |
The user’s last connection closes. |
user_leave |
The user leaves the server or is banned. |
Opening a second connection doesn’t send another user_connect, and closing one of several doesn’t send user_disconnect.
Authenticating again on the same connection updates it in place, so the user isn’t counted twice. Authenticating as a different account moves the connection from the old account to the new one.
Status
Section titled “Status”A user sets their status with status_set:
| Status | Meaning |
|---|---|
online |
Available. |
idle |
Away. |
dnd |
Do not disturb. |
invisible |
Connected, but shown as offline to most people. |
offline |
Shown as offline, like invisible. |
Status can include up to 100 characters of text. A user with no open connections always appears offline.
Visibility
Section titled “Visibility”invisible and offline hide a connected user. Who can see through that depends on the viewer:
- The user themselves and anyone with
manage_userssee the real status and the user’sclientsanddevices. - Everyone else sees
offlinewith empty status text, and emptyclientsanddeviceslists. - Public HTTP user pages have no viewer, so they always show empty
clientsanddevices.
When a user’s status changes, each viewer gets the events that match what they can see:
| Change | Ordinary viewers get | The user and manage_users viewers get |
|---|---|---|
| Goes invisible or offline | user_disconnect with the hidden user |
status_get, then user_clients |
| Comes back to a visible status | user_connect, then status_get |
status_get, then user_clients |
| Changes between visible statuses | status_get |
status_get, then user_clients |
While a user stays hidden, ordinary viewers get no events about their connections opening or closing.
Access to hidden presence follows the manage_users permission, which roles grant. After a command that can change roles or permissions, the server re-checks every connected viewer. Those commands are role create, update, and delete, user_roles_set, self_role_add and self_role_remove, bans and unbans, config_update, and slash commands. A viewer who gains manage_users receives user_connect for each connected user who is hidden. A viewer who loses it receives user_disconnect for each of them.
Client-list events
Section titled “Client-list events”Each connection can report the app name and device type it’s running on when it authenticates. See authentication metadata for the accepted values. The server combines these into two lists per user:
{ "cmd": "user_clients", "username": "mist", "clients": ["mychat", "mychat-cli"], "devices": ["computer", "mobile"]}clientsholds app names. Connections only add one if they sent it when authenticating.devicesholds device types. If a connection doesn’t send one, the server tries to work it out from the connection’sUser-Agentheader.
Each list is sorted and has no duplicates. The lists aren’t paired, so you can’t tell which app runs on which device. The handshake capability user_metadata_v1 means the server supports these fields and this event.
The server sends user_clients when a connected user’s lists change without their first connection opening or last one closing:
- A new connection adds an app or device that wasn’t listed yet.
- A closing connection removes the last one using an app or device.
The event goes to each viewer who can see the change, including the user’s own other connections. A second connection that adds nothing new sends no event. The first connection and the last disconnection are covered by user_connect and user_disconnect, which carry the lists in their user object.
Handle user_clients like this:
- Replace only that user’s
clientsanddevices. - Don’t change their status, roles, nickname, bot flag, or membership.
- Ignore it if the user has already left. Don’t recreate them.
user_clients is server-sent only. Clients can’t request it, and it has no permission of its own.
These lists are self-reported and only last while the connections are open. The server doesn’t verify them, and they aren’t saved with messages. See the client lifecycle for when to expect each event.
