Documentation

Presence

List connections in a segment and observe presence notifications, which are not a complete user roster.

Before you start: complete Messaging. Use its channel and chat objects, with credentials that grant read access to chat. Register listeners before you connect. Request a listing only after the channel is connected.

Presence describes connections, not unique people. A user with three connections appears three times, each with its own connection_id.

1. Register a listener and hold presence interest

from useceleris_client import PresenceEvent


def show_presence(event: PresenceEvent) -> None:
    print("Joined" if event.joined else "Left", event.token_reference, event.connection_id)


stop_presence = chat.on_presence(show_presence)
presence_subscription = chat.subscribe_presence()

on_presence() registers a local listener. subscribe_presence() requests notifications. Keep both while you need them. event.joined is a bool, and event.timestamp is an int in Unix milliseconds. The identifiers are strings.

A presence subscription does not join the segment. It does not give you messages, and your connection does not show in the presence of that segment because of it. To receive the messages of the segment, also call subscribe(). A publish does not join the segment. A connection that only publishes does not show in the presence of that segment.

The server sends presence events as follows:

  • A connection does not get the join event that it causes. A different connection of the same token gets it.
  • When a connection unsubscribes from a segment, watchers get a leave event with the same connection_id as the join. The connection stays connected.
  • On default, a connection causes a join when it connects and a leave when it closes. The default presence list includes all connections of the channel.
  • After a reconnect, watchers get a leave for the previous connection_id and a join for the new one. The SDK subscribes again to the presence that you hold with subscribe_presence().

2. Fetch a snapshot

After you connect, request the first page:

from useceleris_client import CelerisError

try:
    page = await chat.presence_list(page=1, per_page=25)
except CelerisError as error:
    print("Presence query failed:", error.code, error)
else:
    print("Connections:", page.total)
    print("Page:", page.current_page)

    for connection in page.connections:
        print(connection.token_reference, connection.connection_id)

A query does not require a held presence subscription, but it does require an established connection and read permission.

FieldPython typeMeaning
totalintReported connection count
per_pageintPage size reported by the server
current_pageintCurrent page number
from_, tointRange reported for this page
connectionstuple[PresenceConnection, ...]Connection records, not unique users
connections[i].timestampintUnix milliseconds for that connection

from_ ends with an underscore because from is a Python keyword.

3. Paginate and handle failures

Both arguments must be int values: page from 1 to 2,147,483,647 and per_page from 1 to 100. The SDK rejects booleans, floats, strings, and out-of-range values with ConfigurationError. It does not convert or clamp them.

from useceleris_client import PresenceConnection, Segment


async def list_connections(segment: Segment) -> list[PresenceConnection]:
    connections: list[PresenceConnection] = []
    page_number = 1

    while True:
        page = await segment.presence_list(page=page_number, per_page=25)
        connections.extend(page.connections)

        if not page.connections or page.to >= page.total:
            return connections

        page_number += 1


connections = await list_connections(chat)
print("Records fetched:", len(connections))

Only one query can be in flight per channel, even across segments. Await the first query before you start another. A second simultaneous query raises OperationInProgress.

A server refusal raises a ServerError from presence_list() directly, with sub_type "PRES_LIST". The refusal does not also reach on_error. The default query deadline is ten seconds. A Timeout error or a cancellation of the task that awaits the query frees the query slot. Neither closes the connection, and the SDK ignores a late reply.

The SDK does not retry queries automatically. After a connection loss, issue a new query after recovery. See Reconnection and Recovery.

Past the last page, connections is empty, and from_ > to. Do not interpret that as an error.

Listings aggregate across the cluster, but pages are not an atomic snapshot. Connections can join or leave between requests, so a multi-page result can omit or repeat records. Presence events go to watchers on all server nodes of the channel. But a connection that joined before you subscribed, or while you were disconnected, does not cause an event for you. Refresh listings when current state matters, and do not treat presence as a durable user roster.

4. Release presence resources

presence_subscription.cancel()
stop_presence()

Close the channel when its owner no longer needs it. A connection to default has automatic message membership, but it still needs subscribe_presence() to request presence events.

Next: Errors and troubleshooting.

We use Google cookies for analytics and for advertising measurement, only if you allow them. Until you choose, Google sets no cookies. Refer to our Cookie Policy.