> ## Documentation Index
> Fetch the complete documentation index at: https://learn.social.plus/llms.txt
> Use this file to discover all available pages before exploring further.

# User Presence

> Read and sync user online status with AmityUserPresenceRepository on iOS and Android.

User presence lets iOS and Android apps read whether specific users are currently online. Use it for online badges, visible member lists, or a lightweight "who is online" snapshot.

<Warning>
  The current TypeScript and Flutter SDKs in this checkout do not expose a user presence repository. Use the iOS and Android snippets below only for those platforms.
</Warning>

## Platform Surface

| Platform   | Repository                                    | Main APIs                                                                                                                                       |
| ---------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| iOS        | `AmityUserPresenceRepository()`               | `getUserPresence(userIds:)`, `syncUserPresence(id:viewId:)`, `getSyncingUserPresence()`, `getOnlineUsersCount()`, `getOnlineUsersSnapshot()`    |
| Android    | `AmityCoreClient.newUserPresenceRepository()` | `getUserPresence(userIds)`, `syncUserPresence(userId, viewId)`, `getSyncingUserPresence()`, `getOnlineUsersCount()`, `getOnlineUsersSnapshot()` |
| TypeScript | Not available                                 | Not available                                                                                                                                   |
| Flutter    | Not available                                 | Not available                                                                                                                                   |

## Parameters

| Operation                | Parameter       | Required | Description                                                                                                                            |
| ------------------------ | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `getUserPresence`        | `userIds`       | Yes      | User IDs to read. iOS documents a maximum of 220 IDs per call. Keep Android calls bounded for the same reason.                         |
| `syncUserPresence`       | `id` / `userId` | Yes      | User ID whose presence should be refreshed periodically while visible.                                                                 |
| `syncUserPresence`       | `viewId`        | No       | Stable view identifier. Defaults to `amity-global`; use a custom value when the same user can appear in multiple visible UI locations. |
| `unsyncUserPresence`     | `id` / `userId` | Yes      | User ID to remove from syncing.                                                                                                        |
| `unsyncUserPresence`     | `viewId`        | No       | Must match the `viewId` used when syncing if you passed a custom value.                                                                |
| `unsyncAllUserPresence`  | None            | No       | Stops syncing all user presence tracked by the SDK presence engine.                                                                    |
| `getSyncingUserPresence` | None            | No       | Returns iOS `AnyPublisher<[AmityUserPresence], Error>` or Android `Flowable<List<AmityUserPresence>>`.                                 |
| `getOnlineUsersCount`    | None            | No       | Returns the current count of online users in the network.                                                                              |
| `getOnlineUsersSnapshot` | None            | No       | Returns a point-in-time, paginated snapshot of online users. iOS and Android load users 20 at a time.                                  |

## User Presence Object

| Field          | iOS                      | Android                       | Description                                                        |
| -------------- | ------------------------ | ----------------------------- | ------------------------------------------------------------------ |
| User ID        | `presence.userId`        | `presence.getUserId()`        | The user represented by this presence record.                      |
| Last heartbeat | `presence.lastHeartbeat` | `presence.getLastHeartbeat()` | Last heartbeat timestamp, when available.                          |
| Online state   | `presence.isOnline`      | `presence.isOnline()`         | `true` when the last heartbeat is within the SDK online threshold. |

<Info>
  The SDK limits active presence syncing to 20 user IDs at a time. Unsync users when their row, card, or profile preview is no longer visible.
</Info>

## Read User Presence

Fetch presence for known users as a one-shot read.

<CodeGroup>
  ```swift iOS theme={null}
  let repository = AmityUserPresenceRepository()

  let presences = try await repository.getUserPresence(userIds: [userId])
  for presence in presences {
      let isOnline = presence.isOnline
      let lastHeartbeat = presence.lastHeartbeat
      showSuccessMessage("\(presence.userId): \(isOnline)")
  }
  ```

  ```kotlin Android theme={null}
  val repository = AmityCoreClient.newUserPresenceRepository()

  repository.getUserPresence(listOf(userId))
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe({ presences ->
          presences.forEach { presence ->
              val isOnline = presence.isOnline()
              val lastHeartbeat = presence.getLastHeartbeat()
              showSuccessMessage("${presence.getUserId()}: $isOnline")
          }
      }, { error ->
          showErrorMessage(error = error)
      })
  ```
</CodeGroup>

## Sync User Presence

Sync user presence while users are visible, then unsync them when the UI no longer needs updates.

<CodeGroup>
  ```swift iOS theme={null}
  let repository = AmityUserPresenceRepository()

  let cancellable = repository.getSyncingUserPresence()
      .sink(receiveCompletion: { completion in
          if case let .failure(error) = completion {
              handleError(error)
          }
      }, receiveValue: { presences in
          for presence in presences {
              showSuccessMessage("\(presence.userId): \(presence.isOnline)")
          }
      })

  repository.syncUserPresence(id: userId)

  // Call when the row or screen is no longer visible.
  repository.unsyncUserPresence(id: userId)

  _ = cancellable
  ```

  ```kotlin Android theme={null}
  val repository = AmityCoreClient.newUserPresenceRepository()

  repository.getSyncingUserPresence()
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe({ presences ->
          presences.forEach { presence ->
              showSuccessMessage("${presence.getUserId()}: ${presence.isOnline()}")
          }
      }, { error ->
          showErrorMessage(error = error)
      })

  repository.syncUserPresence(userId)

  // Call when the row or screen is no longer visible.
  repository.unsyncUserPresence(userId)
  ```
</CodeGroup>

## Read Online Users Count And Snapshot

Use the count for a network-wide online total. Use the snapshot when you need actual user objects at the time of the query.

<CodeGroup>
  ```swift iOS theme={null}
  let repository = AmityUserPresenceRepository()

  let count = try await repository.getOnlineUsersCount()
  showSuccessMessage(count)

  let snapshot = try await repository.getOnlineUsersSnapshot()
  let users = snapshot.users

  if snapshot.canLoadMore {
      await snapshot.loadMore()
  }
  ```

  ```kotlin Android theme={null}
  val repository = AmityCoreClient.newUserPresenceRepository()

  repository.getOnlineUsersCount()
      .subscribe({ count ->
          showSuccessMessage(count)
      }, { error ->
          showErrorMessage(error = error)
      })

  repository.getOnlineUsersSnapshot()
      .subscribe({ snapshot ->
          val users = snapshot.getUsers()
          if (snapshot.canLoadMore()) {
              snapshot.loadMore().subscribe()
          }
      }, { error ->
          showErrorMessage(error = error)
      })
  ```
</CodeGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Start the current user's heartbeat" icon="heart-pulse">
    Other users can only see the current user as online if the app enables presence and starts the current user's heartbeat. See <a href="/social-plus-sdk/core-concepts/realtime-communication/presence-state/heartbeat-sync">Heartbeat Sync</a>.
  </Accordion>

  <Accordion title="Sync only visible users" icon="eye">
    Bind `syncUserPresence` to visible UI rows, cells, or cards. Call `unsyncUserPresence` during cell reuse, unmount, or screen dismissal.
  </Accordion>

  <Accordion title="Use snapshots for discovery, not live badges" icon="camera">
    `getOnlineUsersSnapshot` is a point-in-time read. For live online badges, sync specific visible users instead.
  </Accordion>
</AccordionGroup>

## Related Topics

<CardGroup cols={2}>
  <Card title="Channel Presence" icon="messages-square" href="/social-plus-sdk/core-concepts/realtime-communication/presence-state/channel-presence">
    Show whether any other member of a conversation channel is online.
  </Card>

  <Card title="Heartbeat Sync" icon="heart-pulse" href="/social-plus-sdk/core-concepts/realtime-communication/presence-state/heartbeat-sync">
    Mark the current user as online with the SDK heartbeat.
  </Card>
</CardGroup>
