---
source_url: https://www.pubnub.com/docs/chat/swift-chat-sdk/build/features/users/presence
title: Presence
updated_at: 2026-06-04T11:09:44.876Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Presence

Track which users are online and active in your chat app. Display user status (online, offline, active, away) and show when users were last active.

The Chat SDK provides two types of presence tracking:

| Type | Description | Data source |
| --- | --- | --- |
| [Channel presence](#channel-presence) | Real-time tracking of users subscribed to specific channels | [Presence API](https://www.pubnub.com/docs/sdks/swift/api-reference/presence) |
| [Global presence](#global-presence) | App-wide activity tracking based on timestamps | [lastActiveTimestamp](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/user) property |

**Channel presence** provides real-time updates through the Presence API. Use [streamPresence()](#get-presence-updates) to track who connects or disconnects.

**Global presence** uses the `lastActiveTimestamp` property on `User` objects. Configure the update interval (default: 10 minutes, minimum: 1 minute) during [initialization](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#input-parameters) with `storeUserActivityTimestamps`.

## Channel presence

These methods let you monitor who is subscribed to a given channel ("present" on that channel).

:::note Requires Presence
All channel presence methods in this section require that [Presence is enabled](https://youtu.be/i2yLIqmvFD0) for your app's keyset in the [Admin Portal](https://admin.pubnub.com/).
:::

You can retrieve similar information for presence with different methods by calling them on the `User`, `Channel`, or `Chat` object. Depending on the chosen method, you must provide a different input information set.

### Return channels where user is present

Return a list of channels where a given user is present:

* `wherePresent()` on the `User` object
* `wherePresent()` on the `Chat` object

#### Method signature

These methods take the following parameters:

* wherePresent() (on the User object) 1user.wherePresent() async throws -> [String]
* wherePresent() (on the Chat object) 1chat.wherePresent(2 userId: String3) async throws -> [String]

##### Input

| Parameter | Required in the `User` object method | Required in the `Chat` object method | Description |
| --- | --- | --- | --- |
| `userId`Type: `String`Default: n/a | No | Yes | [Unique identifier](https://www.pubnub.com/docs/general/setup/users-and-devices#user-id-usage) (up to 92 UTF-8 characters) of the user whose presence you want to check. |

##### Output

| Parameter | Description |
| --- | --- |
| `[String]` | List of all channel IDs on which the given user is present. |

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get a list of channels on which the `support_agent_15` user is present.

* wherePresent() (on the User object) // Assumes a "ChatImpl" reference named "chat" Task { if let user = try await chat.getUser(userId: "support_agent_15") { let channels = try await user.wherePresent() debugPrint("User is present in the following channels: \(channels)") } else { debugPrint("User not found") } }
* wherePresent() (on the Chat object) // Assumes a "ChatImpl" reference named "chat" Task { let channels = try await chat.wherePresent(userId: "support_agent_15") debugPrint("User \"support_agent_15\" is present in the following channels: \(channels)") }

### Check user's channel presence

Check if a user is present on a specified channel:

* `isPresentOn()` on the `User` object
* `isPresent()` on the `Channel` object
* `isPresent()` on the `Chat` object

#### Method signature

These methods take the following parameters:

* isPresentOn() (on the User object) 1user.isPresentOn(2 channelId: String3) async throws -> Bool
* isPresent() (on the Channel object) 1channel.isPresent(2 userId: String 3) async throws -> Bool
* isPresent() (on the Chat object) 1chat.isPresent(2 userId: String,3 channelId: String4) async throws -> Bool

##### Input

| Parameter | Required in the `User` object method | Required in the `Channel` object method | Required in the `Chat` object method | Description |
| --- | --- | --- | --- | --- |
| `userId`Type: `String`Default: n/a | No | Yes | Yes | [Unique ID](https://www.pubnub.com/docs/general/setup/users-and-devices) (up to 92 UTF-8 characters) of the user whose presence you want to check. |
| `channelId`Type: `String`Default: n/a | Yes | No | Yes | Unique identifier of the channel where you want to check the user's presence. |

##### Output

| Parameter | Description |
| --- | --- |
| `Bool` | Returns information on whether a given user is present on a specified channel (`true`) or not (`false`) or an error. |

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Find out if the `support_agent_15` user is present on the `support` channel.

* isPresentOn() (on the User object) // Assumes a "ChatImpl" reference named "chat" let userId = "support_agent_15" let channelId = "support_channel_123" Task { if let user = try await chat.getUser(userId: userId) { let isPresent = try await user.isPresentOn(channelId: channelId) debugPrint("User is present on the channel \(channelId): \(isPresent)") } else { debugPrint("User not found") } }
* isPresent() (on the Channel object) // Assumes a "ChatImpl" reference named "chat" let userId = "support_agent_15" let channelId = "support_channel_123" Task { if let channel = try await chat.getChannel(channelId: channelId) { let isPresent = try await channel.isPresent(userId: userId) debugPrint("User \(userId) is present on the channel \(channelId): \(isPresent)") } else { debugPrint("Channel not found") } }
* isPresent() (on the Chat object) // Assumes a "ChatImpl" reference named "chat" let userId = "support_agent_15" let channelId = "support_channel_123" Task { let isPresent = try await chat.isPresent(userId: userId, channelId: channelId) debugPrint("User \(userId) is present on the channel \(channelId): \(isPresent)") }

### Return all users present on channel

Return a list of users present on a given channel:

* `whoIsPresent()` on the `Channel` object
* `whoIsPresent()` on the `Chat` object

#### Method signature

These methods take the following parameters:

* whoIsPresent() (on the Channel object) 1channel.whoIsPresent(2 limit: Int = 1000,3 offset: Int? = 04) async throws -> [String]
* whoIsPresent() (on the Chat object) 1chat.whoIsPresent(2 channelId: String,3 limit: Int = 1000,4 offset: Int? = 05) async throws -> [String]

##### Input

| Parameter | Required in the `Channel` object method | Required in the `Chat` object method | Description |
| --- | --- | --- | --- |
| `channelId`Type: `String`Default: n/a | No | Yes | Unique identifier of the channel where you want to check all present users. |
| `limit`Type: `Int`Default: `1000` | No | No | Maximum number of occupants to return per channel. Valid range: 0-1000. Use `0` to get occupancy counts without user details. |
| `offset`Type: `Int?`Default: `0` | No | No | Zero-based starting index for pagination. Returns occupants starting from this position in the list. Must be >= 0. |

##### Output

| Parameter | Description |
| --- | --- |
| `[String]` | List of all user IDs that are present on the given channel. |

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get a list of users that are present on the `support` channel.

* whoIsPresent() (on the Channel object) // Assumes a "ChatImpl" reference named "chat" Task { if let channel = try await chat.getChannel(channelId: "support_channel_123") { let userIds = try await channel.whoIsPresent() debugPrint("Users present on the channel: \(userIds)") } else { debugPrint("Channel not found") } }
* whoIsPresent() (on the Chat object) // Assumes a "ChatImpl" reference named "chat" Task { let userIds = try await chat.whoIsPresent(channelId: "support_channel_123") debugPrint("Users present on the channel: \(userIds)") }

### Get presence updates

Get real-time presence updates by [subscribing to Presence events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel). Use `onPresenceChanged()` to track who connects to or disconnects from the channel via a closure, or `channel.stream.presenceChanges()` for an `AsyncStream`-based approach.

:::note Deprecation
`streamPresence()` is deprecated. Use `onPresenceChanged()` (closure-based) or `channel.stream.presenceChanges()` (AsyncStream-based) instead.
:::

#### Method signature

```swift
channel.onPresenceChanged(
    callback: @escaping (Set<String>) -> Void
) -> AutoCloseable
```

##### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: `(Set<String>) -> Void`Default: n/a | Closure called with the set of user IDs currently present on the channel whenever the presence state changes. |

##### Output

| Parameter | Description |
| --- | --- |
| `AutoCloseable` | An object you must retain. When released or closed, the listener stops. |

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Get user presence updates on `support` channel.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let channel = try await chat.getChannel(channelId: "support") {
    for await userIds in channel.streamPresence() {
      debugPrint("Current users present on 'support' channel: \(userIds)")
    }
  } else {
    debugPrint("Channel not found")
  }
}
```

:::note Presence update delay
Closing the `AutoCloseable` cancels the local subscription — it does not push an immediate update to other subscribers. The delay other clients experience before seeing the presence change depends on network propagation and is outside the SDK's control.
If [Presence Deltas](https://www.pubnub.com/docs/general/presence/overview#configuration) are enabled and channel occupancy exceeds the **Announce Max** threshold, individual `leave` events are replaced by batched `interval` events. In that case, other subscribers see the update at the next scheduled interval. To reduce this window, lower the **Interval** value in your keyset's [Presence settings](https://admin.pubnub.com/).
:::

## Global presence

Track users' last online activity to display availability status (offline, online, active, away) next to user profiles.

This feature relies on the [lastActiveTimestamp](https://www.pubnub.com/docs/chat/swift-chat-sdk/learn/chat-entities/user) property on the `User` object. To enable tracking, configure during [Chat SDK initialization](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#initialize-pubnub):

* Set `storeUserActivityTimestamps` to `true`
* Configure `storeUserActivityInterval` for update frequency (default: 600 seconds/10 minutes, minimum: 60 seconds/1 minute)

Use the `active` property to check if a user showed activity within the configured interval.

### Check user's app presence

`active` is a getter property on the `User` object that checks whether a user has recently been active based on their last activity timestamp and the configured interval.

:::note Required configuration
To track the user's online activity, you must first configure the `storeUserActivityTimestamps` and `storeUserActivityInterval` parameters when [initializing the Chat SDK](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#initialize-pubnub).
:::

#### Method signature

This method has the following signature:

```swift
user.active
```

##### Input

This method doesn't take any parameters.

##### Output

| Parameter | Description |
| --- | --- |
| `Bool` | Returned info on whether the user is active (`true`) or not active (`false`) on the channel. The returned value depends strictly on how you configure your chat app during [initialization](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#initialize-pubnub) - if you set the `storeUserActivityInterval` parameter to the default `600` seconds (10 minutes) and the user has been active in the app within the last 10 minutes (based on their `lastActiveTimestamp` property), the `active` method returns `true`. |

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Check if the user `support_agent_15` has been recently active (assuming you configured the chat app to use the default activity interval value).

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let user = try await chat.getUser(userId: "support_agent_15") {
    if user.active {
      debugPrint("User \(user.id) is currently active.")
    } else {
      debugPrint("User \(user.id) is currently not active.")
    }
  } else {
    debugPrint("User not found")
  }
}
```

### Check user's last online activity

:::note Required configuration
To track the user's online activity, you must first configure the `storeUserActivityTimestamps` and `storeUserActivityInterval` parameters when [initializing the Chat SDK](https://www.pubnub.com/docs/chat/swift-chat-sdk/build/configuration#initialize-pubnub).
:::

Retrieve the `lastActiveTimestamp` from the `User` object and convert it to a human-readable date to display when a user was last online.

#### Sample code

:::tip Sample code
The code samples in Swift Chat SDK focus on asynchronous code execution.
You can also write synchronous code as the parameters are shared between the async and sync methods but we don't provide usage examples of such.
:::

Show the Unix timestamp when `support_agent_15` was last time active in an app.

```swift
// Assumes a "ChatImpl" reference named "chat"
Task {
  if let user = try await chat.getUser(userId: "support_agent_15") {
    debugPrint("Fetched user metadata with ID: \(user.id)")
    debugPrint("Last active timestamp: \(user.lastActiveTimestamp)")
  } else {
    debugPrint("User not found")
  }
}
```