Skip to main content
Room presence lets you show who is watching a live room and how many viewers are present at one moment — the building blocks for a “Who’s Watching” list and a live viewer count on a livestream or co-hosted room. Each viewer periodically sends a lightweight heartbeat while they are in the room. The server keeps the set of currently-active viewers, and your app reads that set as a count and as a list of users.
Platform availability. Room presence is available on iOS, Android, and the TypeScript SDK (Web and React Native). It is not yet available on Flutter.

Overview

Send Heartbeat

Mark the current user as present in the room while they are watching.

Viewer Count

Read how many users are currently watching, with optional live updates.

Who's Watching

Fetch the list of users currently present in the room.

Quick Start

1

Create a room presence reference

Identify the room you want to track by its roomId.
2

Start the heartbeat when the viewer enters

Call startHeartbeat when the user opens the room screen. The first heartbeat is sent immediately and then repeats automatically.
3

Read the count and the who's-watching list

Display the live viewer count and, optionally, the list of present users.
4

Stop the heartbeat when the viewer leaves

Call stopHeartbeat when the user closes the room or the screen goes to the background.

Send a Heartbeat

Start a heartbeat when the viewer enters the room, and stop it when they leave. The SDK sends the first heartbeat immediately and then repeats it automatically at a server-controlled interval — you do not configure the interval.
let roomPresence = AmityRoomPresenceRepository(roomId: "<room-id>")

// Start when the viewer enters the room
Task { @MainActor in
    do {
        try await roomPresence.startHeartbeat()
    } catch {
        // Room presence may be disabled for this network
        print("Failed to start room presence: \(error)")
    }
}

// Stop when the viewer leaves
roomPresence.stopHeartbeat()

Get the Viewer Count

getRoomUserCount returns the number of users currently present. This is the authoritative “how many are watching” value.
let count = try await roomPresence.getRoomUserCount()

Keep the count live

The count is a point-in-time read. To keep a viewer badge up to date, poll it on an interval — we recommend about every 30 seconds. Polling more frequently than this is discouraged because it won’t return a more up-to-date count. On Android the SDK provides a built-in polling stream — pass interval = 30 (it defaults to 15 seconds). On iOS and TypeScript, call getRoomUserCount on your own ~30-second interval.
Why 30 seconds? Viewers heartbeat roughly every 30 seconds, and a viewer is counted as present for up to 60 seconds after their last heartbeat. The underlying set of present users only changes as heartbeats arrive and expire, so the count can’t get any fresher by polling faster — anything below ~30 seconds returns the same value with no meaningful update.
// Poll on your own timer (e.g. every 30s)
let timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { _ in
    Task { @MainActor in
        if let count = try? await roomPresence.getRoomUserCount() {
            // update UI
        }
    }
}

Get the “Who’s Watching” List

getRoomOnlineUsers returns the users currently present in the room as full user objects — ideal for rendering avatars or a “Who’s Watching” panel.
let users = try await roomPresence.getRoomOnlineUsers()
// users: [AmityUser]
The list is capped; the count is not. The who’s-watching list returns up to a maximum of 200. The viewer count is not capped, so for rooms with large audiences it can be higher than the number of users in the list. Use the count for the total number of viewers, and the list for showing faces.

Behavior to Know

A user is present while their heartbeat is recent — they are considered online if active within the last ~60 seconds. When a viewer leaves the room or disconnects, the server clears their presence automatically; you don’t need to remove them manually beyond calling stopHeartbeat.
The SDK sends the first heartbeat immediately when you call startHeartbeat, then repeats at a cadence provided by the server. There is no client-side interval to configure.
The count and the list come from separate reads taken at slightly different moments, and the list is capped (see above). Treat the count as the source of truth for totals and the list as a best-effort snapshot of recent viewers.
You can call getRoomUserCount and getRoomOnlineUsers to observe a room even if the current user is not sending a heartbeat themselves (for example, a moderator dashboard). Send a heartbeat only when you want the current user to be counted as present.

Best Practices

Start the heartbeat when the player screen becomes visible and stop it when it is dismissed, backgrounded, or the view model is torn down. Only run it for live rooms — skip recorded/ended playback. If the screen can switch rooms or the viewer’s role changes, stop the old heartbeat and start a fresh one. This keeps the viewer count accurate and avoids counting users who have left.
Polling the count too frequently adds little benefit. A good rule of thumb: ~30s. Slow it down further on screens where the count is secondary.
Load the list when a host opens a viewers or invite-co-host panel, and refetch to refresh. Don’t keep it cached — presence changes constantly, so a stale list is misleading.

Use Cases

Livestream viewer count

Show a live “1,240 watching” badge on a livestream or co-hosted room.

Who's Watching panel

Render avatars of the most recent viewers present in the room.

Co-host invitations

Surface currently-watching viewers so a host can invite one as a co-host.