---
source_url: https://www.pubnub.com/docs/presence/presence-events
title: Presence events
updated_at: 2026-10-06T06:53:17.000Z
---

# Presence events

> For AI agents: documentation index at https://www.pubnub.com/llms-full.txt

Presence events are how [Presence](https://www.pubnub.com/docs/presence/overview.md) reports a client's lifecycle on a [channel](https://www.pubnub.com/docs/architecture/core-concepts.md#channel):

* arriving
* leaving
* going quiet
* changing its state

PubNub delivers them on the channel's `-pnpres` companion channel, through the same [event listener](https://www.pubnub.com/docs/pub-sub/subscribe/event-listeners.md) you already use for messages and signals. This page explains:

* the five event subtypes delivered on the `-pnpres` channel, and what their payloads carry
* the `active` and `inactive` channel events, and why they're delivered elsewhere
* how a channel's occupancy switches it between announce mode and interval mode
* how presence deltas add who changed to an interval event
* how `presenceTimeout` and `heartbeatInterval` decide when a `timeout` event fires

Every presence event requires you to enable [Presence](https://www.pubnub.com/docs/presence/overview.md), which tracks who is online on a channel, on your keyset. If you track selected channels only, a presence rule must match the channel and include the event type, as described in [Presence](https://www.pubnub.com/docs/presence/overview.md#turn-on-presence-without-writing-code).

To receive the five `-pnpres` event subtypes, also enable `receivePresenceEvents` on the channel subscription. To receive `active` and `inactive`, subscribe to the keyset's [Active Notice Channel](https://www.pubnub.com/docs/presence/overview.md#turn-on-presence-without-writing-code), which collects channel-level events for the whole keyset.

For how presence data is enabled and delivered, and how it relates to occupancy and presence state, refer to [Presence](https://www.pubnub.com/docs/presence/overview.md). For the subscription call and listener setup, refer to [Receive presence events](https://www.pubnub.com/docs/presence/receive-presence-events.md).

## Event subtypes delivered on the -pnpres channel

| Subtype | Fires when |
| --- | --- |
| `join` | A client subscribes to the channel |
| `leave` | A client unsubscribes from the channel |
| `timeout` | A client goes silent for longer than the channel's heartbeat timeout allows |
| `state-change` | A client's [presence state](https://www.pubnub.com/docs/presence/set-and-get-presence-state.md) changes |
| `interval` | The channel is in interval mode and reports occupancy on a fixed schedule |

Every presence event names the `channel` it happened on, carries the channel's current `occupancy`, and stamps a [timetoken](https://www.pubnub.com/docs/architecture/core-concepts.md#timetoken). Most also carry the `uuid` of the client whose presence changed, identified by [User ID](https://www.pubnub.com/docs/architecture/core-concepts.md#user-id).

`interval` events are the exception: they describe the channel as a whole rather than one client, so they carry no `uuid`. A `state-change` event also carries a `data` field holding the state that changed.

The following illustrates the payload for each subtype that fires individually in announce mode:

### join

```json
{
  "action": "join",
  "channel": "chats.room1",
  "occupancy": 3,
  "uuid": "user123",
  "timetoken": "17511946699655811"
}
```

### leave

```json
{
  "action": "leave",
  "channel": "chats.room1",
  "occupancy": 2,
  "uuid": "user123",
  "timetoken": "17511946699812340"
}
```

### timeout

```json
{
  "action": "timeout",
  "channel": "chats.room1",
  "occupancy": 1,
  "uuid": "user456",
  "timetoken": "17511947001234567"
}
```

### state-change

```json
{
  "action": "state-change",
  "channel": "chats.room1",
  "occupancy": 3,
  "uuid": "user123",
  "timetoken": "17511947895378127",
  "data": {
    "mood": "grumpy"
  }
}
```

Field names are typed per SDK, not platform-wide. For the exact shape your handler receives, refer to the API reference for your platform in [Available SDKs](https://www.pubnub.com/docs/sdks.md).

## Channel active and inactive events

Two more subtypes describe the channel as a whole rather than a single client. PubNub doesn't deliver them on `-pnpres`.

| Subtype | Fires when |
| --- | --- |
| `active` | A channel gets its first occupant (occupancy goes from 0 to 1 or more) |
| `inactive` | The last occupant leaves a channel (occupancy goes from 1 or more to 0) |

Your presence event listener doesn't receive `active` and `inactive`, because PubNub doesn't deliver them on the channel's `-pnpres` channel. PubNub publishes them as messages on the keyset's **Active Notice Channel**, which you set in the keyset's [Presence configuration](https://www.pubnub.com/docs/presence/overview.md#turn-on-presence-without-writing-code). That channel receives these events from every channel on the keyset.

To receive them, subscribe to the Active Notice Channel like any other channel. Clients get them only while subscribed. To fetch them later, enable **Include presence events** in [Message Persistence](https://www.pubnub.com/docs/data-storage/message-history/overview.md) settings and [retrieve them from history](https://www.pubnub.com/docs/data-storage/message-history/retrieve-message-history.md).

## Channel occupancy decides announce mode or interval mode

Below the Announce Max threshold, a channel emits individual `join`, `leave`, and `timeout` events. At or above it, the channel emits periodic `interval` events instead, while `state-change` stays individual in both modes.

Interval mode exists so a busy channel's presence traffic doesn't emit thousands of join, leave, and timeout events for ordinary churn. You configure the occupancy threshold and the interval's cadence per keyset in [Presence Management](https://www.pubnub.com/docs/presence/overview.md#turn-on-presence-without-writing-code), not in your application code. For the threshold's default and maximum values and the interval cadence limits, refer to [API limits](https://www.pubnub.com/docs/architecture/limits.md#presence). To see what stays accurate on [Here Now](https://www.pubnub.com/docs/presence/get-online-users-in-channel.md) after a channel crosses that threshold, refer to [Occupancy](https://www.pubnub.com/docs/presence/occupancy.md#occupancy-on-a-channel-in-announce-vs-interval-mode).

## Presence deltas add who changed to an interval event

By default, an `interval` event carries only a total `occupancy` count. Suppressing individual join, leave, and timeout events is the whole point of interval mode.

Enabling Presence Deltas in [Admin Portal](https://admin.pubnub.com/) adds three arrays to each `interval` event:

* `join`
* `leave`
* `timeout`

Each array lists the User IDs that changed since the previous interval:

```json
{
  "action": "interval",
  "channel": "chats.megachat",
  "occupancy": 27,
  "timetoken": "17511947739621090",
  "join": ["user123", "user88"],
  "leave": ["user20", "user11"],
  "timeout": ["user42"],
  "hereNowRefresh": false
}
```

The standard message payload size limit is 32 KiB. This includes the channel name and any metadata. An interval event's delta arrays count toward that limit alongside the rest of the payload. If the arrays would push the event over the limit, PubNub drops them and sets `hereNowRefresh: true` instead.

Treat that flag as a signal to call `Here Now`, since the deltas you needed didn't arrive. Refer to [Get online users in a channel](https://www.pubnub.com/docs/presence/get-online-users-in-channel.md) for more details.

## Heartbeats decide when a timeout event fires

A `timeout` event depends on a per-client timer, not on network-level disconnect detection. PubNub SDKs set `presenceTimeout` to 300 seconds by default, which is how long PubNub waits without a heartbeat before marking a client offline. Anything that resets the timer before it expires keeps the client marked online. Letting it expire is what fires `timeout`.

Two settings control the timeout timer:

* `presenceTimeout` (also `presenceHeartbeatValue` or `durationUntilTimeout` in some SDKs) is the timer itself. It sets how long PubNub waits without a heartbeat before marking a client offline and emitting `timeout`.
* `heartbeatInterval` (also `presenceHeartbeatInterval`) is how often the client sends a dedicated explicit heartbeat through the [Presence Heartbeat API](https://www.pubnub.com/docs/sdks/rest-api/announce-heartbeat.md) to reset that timer on demand. Explicit presence heartbeats are off by default in PubNub SDKs, because `heartbeatInterval` defaults to `0`.

Every subscribe call also resets the timer as an implicit heartbeat, whether or not `heartbeatInterval` is set. A client that's actively subscribing has already proven it's there, so leaving `heartbeatInterval` at its default works for most applications. Only a client that stops subscribing entirely drifts toward `timeout`.

Explicit heartbeats detect a disconnect sooner than implicit ones alone. A subscribe connection can sit idle for up to the platform's long-poll window before the SDK reissues it. A client that disconnects right after that window starts stays marked online until the rest of `presenceTimeout` also elapses. Setting `heartbeatInterval` shorter than that window closes the gap. Each heartbeat is a billable API call, and every connected client makes one on that schedule.

Set `heartbeatInterval` if your application needs to detect a disconnect quickly. Leave it at its default if an active user's own subscribe traffic already proves them present, as in most chat apps.

Some SDKs derive `heartbeatInterval` from `presenceTimeout` once you set `presenceTimeout`, instead of leaving it at its default. Check your SDK's configuration reference before assuming you get the default.

For the mechanics of implicit heartbeats and what a disconnect looks like to other clients, refer to [Connection management](https://www.pubnub.com/docs/architecture/connection-management/overview.md#implicit-heartbeats-and-the-presence-timeout). For the minimum values SDKs enforce on both settings, refer to [API limits](https://www.pubnub.com/docs/architecture/limits.md#presence).

Presence timeout detection is local, not regional. It doesn't depend on which region a client connects through. PubNub SDKs don't actively poll a client's connectivity. A disconnect is detected only when a subscribe request times out or the next request fails. That's a property of the client's own connection, not of PubNub's monitoring.

## Next steps

* [Presence](https://www.pubnub.com/docs/presence/overview.md). How presence data is enabled and delivered, and how it relates to occupancy, state, and membership.
* [Occupancy](https://www.pubnub.com/docs/presence/occupancy.md). What a `Here Now` response contains and why it stays accurate once a channel switches to interval mode.
* [Receive presence events](https://www.pubnub.com/docs/presence/receive-presence-events.md). Subscribe to a channel with presence events enabled and register a listener.
* [Get online users in a channel](https://www.pubnub.com/docs/presence/get-online-users-in-channel.md). Call `Here Now` to look up current occupancy on demand.
* [Set and get presence state](https://www.pubnub.com/docs/presence/set-and-get-presence-state.md). Attach and read the custom state that triggers `state-change`.
* [Presence Management](https://www.pubnub.com/docs/presence/overview.md#turn-on-presence-without-writing-code). Configure which channels and event types generate presence events.
* [Connection management](https://www.pubnub.com/docs/architecture/connection-management/overview.md). Implicit heartbeats, reconnection, and what other clients see when you disconnect.
* [API limits](https://www.pubnub.com/docs/architecture/limits.md#presence). Announce max, interval cadence, and heartbeat limits.

Last updated at: 2026-10-06T06:53:17.000Z
