---
source_url: https://www.pubnub.com/docs/general/presence/presence-events
title: Presence Events
updated_at: 2026-06-04T11:10:23.638Z
---

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

PubNub sends Presence events when users come online or go offline in your app.

You can receive these events in the client or use webhooks to keep a user's online and offline status up to date. Use presence events to track active and inactive users and the total occupancy of the channel.

:::tip Presence webhooks
PubNub can invoke a REST endpoint on your server when presence events occur. For more information, refer to [Events & Actions](https://www.pubnub.com/docs/serverless/events-and-actions/events#webhooks).
:::

###### Receive presence events alongside messages

PubNub delivers presence events through dedicated `-pnpres` channels using the same real-time infrastructure as regular messages. Your app handles them with the same [event listener](https://www.pubnub.com/docs/general/messages/receive#add-an-event-handler) pattern you use for messages and signals, which means presence integrates into your existing subscription code without a separate delivery path.

## Presence event types

There are five main types of presence events:

| Events | Description |
| --- | --- |
| `join` | Sent when a user subscribes to a channel. |
| `leave` | Sent when a user unsubscribes from a channel. |
| `timeout` | Sent when a subscriber is inactive on a channel for a set period. Default is 300 seconds for most SDKs. Configure the interval with [presenceTimeout](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration#initialization). Optionally send heartbeats using [heartbeatInterval](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration#initialization) to keep connections active and avoid timeouts. |
| `state-change` | Sent when a user's state changes. |
| `interval` | Sent in interval mode with occupancy and optional deltas. |

:::note Timeout detection
Presence timeout detection is not region-dependent. PubNub SDKs don't actively monitor connectivity. A disconnection is detected when subscribe requests time out (typically 300 seconds) or when the next request fails. Local network conditions drive timing differences, not PubNub's system.
:::

## Implicit vs. explicit Presence events

When you work with Presence, your app can signal that users are online in two ways. Think of a coffee shop: you can wave every few minutes (explicit) or people will see you when you move around (implicit).

First, understand how Presence tracking works. PubNub uses a timer for each user to decide when to mark them offline. The key is what resets this timer and how you configure the timeout.

PubNub tracks user activity automatically. Each subscribe call tells PubNub the user is active. This is implicit Presence and it runs by default. You can disable implicit heartbeats in the [Presence Management](https://www.pubnub.com/docs/bizops-workspace/presence-management) page in the Admin Portal by clearing the `Subscribe Heartbeats` checkbox.

PubNub runs a timer per user. Each implicit heartbeat from the [Subscribe API](https://www.pubnub.com/docs/sdks/rest-api/subscribe-v-2) resets the timer. If a user is silent for the full duration, PubNub marks the user offline and sends a `timeout` event. The `presenceTimeout` setting controls this duration. It applies to both implicit heartbeats (Subscribe API) and explicit heartbeats ([Presence Heartbeat API](https://www.pubnub.com/docs/sdks/rest-api/announce-heartbeat)).

Why configure anything if PubNub tracks activity automatically? You may need faster disconnect detection than the default server ping interval (~280 seconds). Two settings determine when users are marked offline.

### Configuration settings

Before we dive deeper, let's understand the two main configuration options and how they work together:

* presenceTimeout (also presenceHeartbeatValue or durationUntilTimeout in some SDKs) is the server-side timer. It sets how long PubNub waits without a subscribe call before marking a user offline. Default is about 300 seconds. Any explicit (heartbeat API) or implicit (subscribe API) heartbeat resets this timer.
* heartbeatInterval (sometimes presenceHeartbeatInterval) is the client-side ping frequency. It controls dedicated "I'm still here" signals via the heartbeat API. 0 (default) sends no explicit pings and relies on implicit heartbeats. Any positive value (min 3 seconds) sends explicit heartbeats at that interval.

Think of it this way: `presenceTimeout` is like a countdown clock on PubNub's servers, and `heartbeatInterval` is like setting an alarm on your phone to reset that clock before it runs out.

Now let's see how these work in practice. If you set your `presenceTimeout` to 300 seconds and a user's client sends an implicit heartbeat (via subscribe API) after 4 minutes of being idle, PubNub resets their timer back to zero. They won't time out until they've been completely inactive for another full timeout period. This is actually pretty smart - if someone is actively subscribed to your app, why mark them as offline?

### When implicit Presence isn't enough

Relying only on implicit Presence can delay disconnect detection. By default, the server expects the client to respond to a published message or an empty server ping every ~280 seconds. These [server pings](https://www.pubnub.com/docs/sdks/rest-api/presence-introduction#long-running-heartbeat-calls) reset the long‑poll and act as implicit heartbeats. You may wait up to the full `presenceTimeout` (~300 seconds) before detecting a disconnect.

Explicit heartbeats help here. Set `heartbeatInterval` shorter than the server ping (for example, 120 seconds). The SDK then sends "I'm still here" signals more often. These explicit heartbeats reset the same Presence timeout and detect disconnects faster.

```javascript
// Let users rely on natural activity to stay present
{
  presenceTimeout: 300,     // 5 minutes until timeout
  heartbeatInterval: 0      // No explicit heartbeats
}

// Send regular "I'm alive" signals regardless of activity  
{
  presenceTimeout: 300,     // 5 minutes until timeout  
  heartbeatInterval: 120    // Heartbeat every 2 minutes
}
```

### Cost vs. accuracy trade-off

Every heartbeat is an API call. API calls incur cost. 1,000 users with a 60‑second heartbeat create 1,440,000 calls per day. If the default server ping (~280 seconds) is enough for your use case, explicit heartbeats may be unnecessary.

If you need rapid disconnect detection (for example, trading or emergency apps), use shorter heartbeat intervals for faster updates.

### Real-world scenarios

Here's how to configure these settings for different types of applications:

#### Chat applications

Most chat users are naturally active, so you can usually rely on implicit Presence with server pings. Set `heartbeatInterval: 0` and let the default server ping interval (~280 seconds) maintain user presence. If someone's connection drops for your full `presenceTimeout` period, they're probably actually disconnected.

#### Collaborative tools

For applications needing faster disconnection detection than the default ~280-second server ping interval, a shorter heartbeat interval like 120 seconds provides quicker notification when users disconnect. This might cost more but enables faster presence updates.

#### Mobile applications

Battery life matters. You might use a hybrid approach with a longer `presenceTimeout` (like 600 seconds) and longer `heartbeatInterval` (like 240 seconds). This gives inactive users more time before timing out while still sending occasional heartbeats.

#### Critical applications

Trading platforms, emergency communication systems, or real-time monitoring tools need immediate notification when someone disconnects. Use shorter intervals like `heartbeatInterval: 30` with `presenceTimeout: 120` for rapid detection.

### Mixed strategies

Implicit Presence works alongside any explicit heartbeats you configure. This actually works in your favor. Even with `heartbeatInterval: 0`, if users are actively subscribing, they'll stay present. With heartbeats enabled, both implicit heartbeats (via subscribe API) and explicit heartbeats (via presence heartbeat API) will keep the Presence timer reset, giving you the most reliable tracking possible.

The key insight is that `presenceTimeout` works the same way regardless of your heartbeat settings - it's simply the maximum time PubNub waits to hear any sign of life (whether from implicit heartbeats via subscribe API or explicit heartbeats via presence heartbeat API) before marking someone as offline.

Understanding this balance between automatic implicit heartbeats (via subscribe API) and intentional explicit heartbeats (via presence heartbeat API) helps you design a Presence system that matches both your user behavior patterns and your budget constraints.

## Add Presence listeners

Receiving presence events requires a Presence listener. Presence events will be received for all channels within a subscription to which you added the listener and enabled Presence events.

:::note User ID / UUID
User ID is also referred to as **UUID/uuid** in some APIs and server responses but **holds the value** of the **userId** parameter you [set during initialization](https://www.pubnub.com/docs/general/setup/users-and-devices#set-the-user-id).
:::

| Event Data | Description |
| --- | --- |
| action | The Presence event action type: join, leave, timeout, state-change, interval |
| channel | The channel on which the Presence action happened |
| occupancy | The total number of subscribers on the channel when the event occurred |
| uuid | The User ID of the client that published the message |
| timetoken | The timetoken when the Presence action took place (when PubNub published the event) |
| data | The state of the client that changed |
| subscription | The channel group or wildcard subscription pattern that the channel belongs to (if applicable) |

For code examples, see [Receive Messages](https://www.pubnub.com/docs/general/messages/receive#add-an-event-handler).

###### Use presence timetokens to correlate user activity with messages

Each presence event carries a timetoken marking when PubNub published the event. This value uses the same 17-digit nanosecond format as [message publish timetokens](https://www.pubnub.com/docs/general/messages/publish#send-messages), so you can correlate user arrivals and departures with specific points in message history. Pass a presence event's timetoken to [Message Persistence](https://www.pubnub.com/docs/general/storage#retrieve-messages) to see what messages were flowing on the channel at the moment a user joined or left.

## Subscribe to Presence channel

When you enable the [receivePresenceEvents](https://www.pubnub.com/docs/general/channels/subscribe#subscription-options) option (name may vary by SDK) and subscribe to a channel, the SDK automatically subscribes you to the relevant Presence channels.

:::note Subscription with Presence
To receive Presence events, you [subscribe with Presence](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe) and have Presence enabled on your keyset. Make sure you configure Presence to track [Presence-related events](https://www.pubnub.com/docs/general/presence/overview#configuration) for all or selected channels (through [Presence Management rules](https://www.pubnub.com/docs/bizops-workspace/presence-management)).
:::

Presence channels are sister channels where presence events are published. If you don't wish to subscribe to all presence channels in your list, you can subscribe to individual channels by appending `-pnpres` to the channel name. For example, the presence channel for `ch1` is `ch1-pnpres`.

:::tip Subscribe to presence channel only
To subscribe only to the Presence channel and not the main channel (to avoid increasing its occupancy, for example), subscribe to the main channel's `-pnpres` channel.
:::

After you create the subscription with the `receivePresenceEvents` option enabled and add Presence listeners, call `subscribe()` to start receiving Presence events in real time as users join and leave channels.

###### JavaScript

```javascript
// create a subscription from a channel entity
const channel = pubnub.channel('channel_1')
const subscription1 = channel.subscription({ receivePresenceEvents: true });

// subscribe and start receiving real-time updates
subscription1.subscribe();
```

###### Swift

```swift
// create a subscription from a channel entity
let subscription1 = pubnub.channel("channelName").subscription(options: ReceivePresenceEvents())
// subscribe and start receiving real-time updates
subscription1.subscribe()
```

###### Objective-C

```objectivec
[self.pubnub subscribeToChannels: @[@"chats.room1", @"chats.room2"] withPresence:NO];
```

###### Java

```java
pubnub.subscribe()
  .channels(Arrays.asList("chats.room1", "chats.room2"))
  .withPresence().execute();
```

###### C#

```csharp
SubscriptionSet subscriptionSet = pubnub.Subscription(
    new string[] {"chats.room1", "chats.room2"},
    SubscriptionOptions.ReceivePresenceEvents
)
```

###### Python

```python
subscription_set1 = pubnub.subscription_set(channels=["chats.room1", "chats.room2"])
subscription_set1.subscribe(with_presence = True)
```

###### Kotlin

```kotlin
// create a subscription from a channel entity
val subscription1 = pubnub.channel("channelName").subscription(SubscriptionOptions.receivePresenceEvents())
// subscribe and start receiving real-time updates
subscription1.subscribe()
```

If you want to subscribe to a bunch of channels but only want to listen for presence events on some of them, you can create two subscription sets: one with the `receivePresenceEvents` option enabled for the channels you want to receive Presence updates, and one without the option for channels you don't want to receive the updates. For more information about subscription sets, refer to [Subscription types](https://www.pubnub.com/docs/general/channels/subscribe#subscription-types).

## Presence event modes

The channel presence mode indicates when presence events are triggered for that channel. There are two modes: *announce* and *interval*. The mode is determined by the occupancy count (total actively subscribed clients on that channel) in relation to the Presence *Announce Max* setting on the [Admin Portal](https://admin.pubnub.com).

This feature prevents high occupancy channels from becoming too noisy with presence events. If you require the announce mode to be in effect past 100 occupants, please contact [PubNub Support](https://support.pubnub.com/hc/en-us).

### Announce mode

If the channel occupancy is less than the *Announce Max* setting (defaults to 20), the channel is in announce mode. In this mode, `join`, `leave`, `timeout` and `state-change` events are sent to subscribed clients as and when they're triggered.

:::note User ID / UUID
User ID is also referred to as **UUID/uuid** in some APIs and server responses but **holds the value** of the **userId** parameter you [set during initialization](https://www.pubnub.com/docs/general/setup/users-and-devices#set-the-user-id).
:::

###### Join

```json
{
  "action": "join",
  "channel": "chats.room1",
  "subscribedChannel": "chats.room1-pnpres",
  "timetoken": "15119466699655811",
  "occupancy": 2,
  "uuid": "user123",
  "timestamp": 1511946669
}
```

###### Leave

```json
{
  "action": "leave",
  "channel": "chats.room1",
  "subscribedChannel": "chats.room1-pnpres",
  "timetoken": "15119466699655811",
  "occupancy": 2,
  "uuid": "user123",
  "timestamp": 1511946669
}
```

###### timeout

```json
{
  "action": "timeout",
  "channel": "chats.room1",
  "subscribedChannel": "chats.room1-pnpres",
  "timetoken": "15119466699655811",
  "occupancy": 2,
  "uuid": "user123",
  "timestamp": 1511946669
}
```

###### State Change

```json
{
  "action": "state-change",
  "channel": "room-1",
  "subscription": null,
  "actualChannel": null,
  "subscribedChannel": "room-1-pnpres",
  "state": {
    "mood": "grumpy"
  },
  "timetoken": "15119477895378127",
  "occupancy": 5,
  "uuid": "user1",
  "timestamp": 1511947789
}
```

### Interval mode

When a channel's occupancy exceeds the *Announce Max* setting, the channel switches to interval mode. In this mode, the `join`, `leave`, and `timeout` events are replaced by an `interval` event sent every few seconds with the total occupancy on the channel. You configure the *Interval* setting on the settings page.

:::note Triggering state-change events
The `state-change` events are always triggered regardless of which presence mode is active on a channel.
:::

## Presence deltas

Additionally, you can enable the *Presence Deltas* setting from the [Admin Portal](https://admin.pubnub.com). When this flag is enabled, `interval` events will also include a list of clients (User IDs) that joined, left or timed-out since the last `interval` event. The following is a simple representation of a Presence Delta event payload.

```json
{
  "action": "interval",
  "channel": "chats.megachat",
  "occupancy": 27,
  "join": ["user123","user88"],
  "leave": ["user20", "user11", "user14"],
  "timeout": ["user42"],
  "subscribedChannel": "chats.megachat-pnpres",
  "timestamp": 1511947739,
  "timetoken": "15119477396210903",
  "hereNowRefresh": false
}
```

:::note Here now refresh flag
Both the Presence Deltas on a channel in Interval mode and the [Presence Interval Webhooks](https://www.pubnub.com/docs/serverless/events-and-actions/events#webhook-payload) behave similarly when the payload size exceeds the maximum limit.
If the presence delta data increases the payload beyond the maximum publish size (32 KiB), the excess data is removed, and a `hereNowRefresh` flag is included in the payload. This flag indicates that you should use the [Here Now API](https://www.pubnub.com/docs/sdks/rest-api/check-present-users) to retrieve the list of currently active User IDs.
:::

## Terms in this document

* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Channel pattern** - A way to group and analyze channel data to track performance metrics like message counts and user engagement over time with PubNub Insights.
* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.
* **User ID** - UTF-8 encoded, unique string of up to 92 characters used to identify a single client (end user, device, or server) that connects to PubNub.
