---
source_url: https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence
title: Presence
updated_at: 2026-06-12T11:22:58.293Z
---

> 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/kotlin/api-reference/presence) |
| [Global presence](#global-presence) | App-wide activity tracking based on timestamps | [lastActiveTimestamp](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/user) property |

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

**Global presence** uses the `lastActiveTimestamp` property on `User` objects. Configure the update interval (default: 600 seconds, minimum: 60 seconds) during [initialization](https://www.pubnub.com/docs/chat/kotlin-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

You can return a list of channels where a given user is present with:

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

Both of these methods have the same name and give the same output. The only difference is that you call a given method either on the `Chat` or the `User` object. Depending on the object, you either have to specify the ID of the user whose presence you want to check or not because it's already known.

#### Method signature

These methods take the following parameters:

* wherePresent() (on the User object) 1user.wherePresent(): PNFuture<List<String>>
* wherePresent() (on the Chat object) 1chat.wherePresent(userId: String): PNFuture<List<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

| Type | Description |
| --- | --- |
| `PNFuture<List<String>>` | List of all channel IDs on which the given user is present. |

#### Sample code

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

* wherePresent() (on the User object) 1// reference the "chat" object and invoke the "getUser()" method2chat.getUser("support_agent_15").async { result ->3 result.onSuccess { user ->4 user.wherePresent().async { channelsResult ->5 channelsResult.onSuccess {6 // handle success7 }.onFailure {8 // handle failure9 }10 }11 }.onFailure {12 // handle failure13 }14}
* wherePresent() (on the Chat object) 1// reference the "chat" object and invoke the "wherePresent()" method2chat.wherePresent("support_agent_15").async { result ->3 result.onSuccess {4 // handle success5 }.onFailure {6 // handle failure7 }8}

### Check user's channel presence

You can return information if the user is present on a specified channel with:

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

All of these methods give the same output. The only difference is that you call a given method on the `User`, `Channel`, or `Chat` object. Depending on the object, you have to specify the ID of the user whose presence you want to check, the channel ID where you want to check user's presence, or both user and channel IDs.

#### Method signature

These methods take the following parameters:

* isPresentOn() (on the User object) 1user.isPresentOn(channelId: String): PNFuture<Boolean>
* isPresent() (on the Channel object) 1channel.isPresent(userId: String): PNFuture<Boolean>
* isPresent() (on the Chat object) 1chat.isPresent(userId: String, channelId: String): PNFuture<Boolean>

##### 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

| Type | Description |
| --- | --- |
| `PNFuture<Boolean>` | Returns information on whether a given user is present on a specified channel (`true`) or not (`false`). |

#### Sample code

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

* `isPresentOn()` (on the `User` object)

```kotlin
// reference the "chat" object and invoke the "getUser()" method
chat.getUser("support_agent_15").async { result ->
    result.onSuccess { user ->
        user.isPresentOn("support").async { presenceResult ->
            presenceResult.onSuccess {
                // handle success
            }.onFailure {
                // handle failure
            }
        }
    }.onFailure {
        // handle failure
    }
}
```

* isPresent() (on the Channel object) 1// reference the "chat" object and invoke the "getChannel()" method2chat.getChannel("support").async { result ->3 result.onSuccess { channel ->4 channel.isPresent("support_agent_15").async { presenceResult ->5 presenceResult.onSuccess {6 // handle success7 }.onFailure {8 // handle failure9 }10 }11 }.onFailure {12 // handle failure13 }14}
* isPresent() (on the Chat object) 1// invoke the "isPresent()" method on the "chat" object2chat.isPresent("support_agent_15", "support").async { result ->3 result.onSuccess {4 // handle success5 }.onFailure {6 // handle failure7 }8}

### Return all users present on channel

You can return a list of users present on the given channel with:

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

Both of these methods have the same name and give the same output. The only difference is that you call a given method either on the `Chat` or the `Channel` object. Depending on the object, you either have to specify the ID of the channel where you want to check all present users or not because it's already known.

#### Method signature

These methods take the following parameters:

* whoIsPresent() (on the Channel object) 1channel.whoIsPresent(2 limit: Int = 1000,3 offset: Int? = null4): PNFuture<Collection<String>>
* whoIsPresent() (on the Chat object) 1chat.whoIsPresent(2 channelId: String,3 limit: Int = 1000,4 offset: Int? = null5): PNFuture<Collection<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: `null` | No | No | Zero-based starting index for pagination. Returns occupants starting from this position in the list. Must be >= 0. |

##### Output

| Type | Description |
| --- | --- |
| `PNFuture<Collection<String>>` | List of all user IDs that are present on the given channel. |

#### Sample code

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

* whoIsPresent() (on the Channel object) 1// reference the "chat" object and invoke the "getChannel()" method2chat.getChannel("support").async { result ->3 result.onSuccess { channel ->4 channel.whoIsPresent().async { usersResult ->5 usersResult.onSuccess {6 // handle success7 }.onFailure {8 // handle failure9 }10 }11 }.onFailure {12 // handle failure13 }14}
* whoIsPresent() (on the Chat object) 1// invoke the "whoIsPresent()" method on the "chat" object2chat.whoIsPresent("support").async { result ->3 result.onSuccess {4 // handle success5 }.onFailure {6 // handle failure7 }8}

### Get presence updates

Get up-to-date information about the real-time presence of users in the specified channel by [subscribing to Presence events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel). The `onPresenceChanged()` method lets you constantly track who connects to or disconnects from the channel and visually represent that in your chat app through some status, like `offline`, `online`, `active`, `away`, or any other.

:::warning Deprecated method
`streamPresence()` is deprecated. Use `onPresenceChanged()` instead. Both methods have the same signature and behavior.
:::

#### Method signature

This method takes the following parameters:

```kotlin
channel.onPresenceChanged(callback: (userIds: Collection<String>) -> Unit): AutoCloseable
```

##### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: n/aDefault: n/a | Callback function passed as a parameter. It defines the custom behavior to be executed when detecting new user presence events. |
| → `userIds` *Type: `Collection<String>`Default: n/a | Returns an updated collection of user IDs. |

##### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface that lets you stop receiving presence-related updates (`presence` events) by invoking the `close()` method. |

#### Sample code

Get user presence updates on `support` channel.

```kotlin
// reference the "chat" object and invoke the "getChannel()" method
chat.getChannel("support").async { result ->
    result.onSuccess { channel ->
        // stream presence updates on the "support" channel
        val subscription = channel.onPresenceChanged { userIds ->
            // handle presence updates
        }

        // to stop streaming presence updates, you can call `close` on the subscription
        // subscription.close()
    }.onFailure {
        // handle failure
    }
}
```

:::note Presence update delay
Calling `subscription.close()` 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

The Chat SDK lets you configure your app to track the user's last online activity - this gives near real-time visibility into the availability of other chat members, allowing you to see whether someone is offline or available and reach out to them to start immediate communication.

Using this online activity information provided by the Chat SDK, you can later configure your app to display different statuses next to user profiles, like `offline`, `online`, `active`, `away` or any other.

This feature relies on the [lastActiveTimestamp](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/user) property set in milliseconds on the `User` object. This property stands for the Unix timestamp (numeric value representing the number of seconds since January 1, 1970) for the last time the user was active in a chat app. To track this, you must explicitly state that when configuring your app during the [Chat SDK initialization](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/configuration#initialize-pubnub) by:

* Setting the `storeUserActivityTimestamps` parameter to `true`.
* Deciding how frequently a user's online activity will be updated by configuring the `storeUserActivityInterval` option - the default value is set to `600` seconds (10 minutes) and the minimum value is `60` seconds (1 minute).

If you set these options, you can track a user's global presence through the `active` property that relies on the above setup. If the user showed no online activity within the defined period of time, they are considered inactive.

### Check user's app presence

`active` is a property on the `User` object that lets you check whether a user has recently been active in the chat app based on their last activity timestamp and a 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/kotlin-chat-sdk/build/configuration#initialize-pubnub).
:::

#### Property

```kotlin
val active: Boolean
```

#### Description

Returns `true` if the user is considered active, or `false` if not. The returned value depends strictly on how you configure your chat app during [initialization](https://www.pubnub.com/docs/chat/kotlin-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), `active` returns `true`.

#### Sample code

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

```kotlin
chat.getUser("support_agent_15").async { result ->
    result.onSuccess { user ->
        val isActive = user.active
        if (isActive) {
            // handle the user being recently active
        } else {
            // handle the user not being recently active
        }
    }.onFailure { e ->
        // handle failure in getting user
    }
}
```

### 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/kotlin-chat-sdk/build/configuration#initialize-pubnub).
:::

Let's assume you configured your app to track the user's online activity and update it every 2 minutes. You can retrieve information on the user's last online activity directly from the `User` object, convert it to a human-readable date (using external date and time libraries), and display it next to the user's profile in your chat app. Thanks to that, other app users will be able to see the last time the given user was online.

#### Sample code

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

```kotlin
chat.getUser("support_agent_15").async { result ->
    result.onSuccess { user ->
        val lastActiveTimestamp = user.lastActiveTimestamp
        // use the timestamp appropriately in your application, e.g., update UI
    }.onFailure { e ->
        // handle failure in getting user
    }
}
```