---
source_url: https://www.pubnub.com/docs/presence/overview
title: Presence
updated_at: 2026-09-30T07:20:08.000Z
---

# Presence

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

Presence tells your application who is currently subscribed to a [channel](https://www.pubnub.com/docs/architecture/core-concepts.md#channel), in real time, without polling. You get presence data through the same SDK event listener you already use for messages. No separate connection or subscription is needed. Where [Pub/Sub](https://www.pubnub.com/docs/pub-sub/overview.md) delivers what a client sent, Presence answers a different question: who is here right now and what changed. This page explains:

* how PubNub generates and delivers presence data
* the three things you can do with it: query occupancy, attach live state, and receive change events
* how presence differs from the persistent membership records your application also keeps
* how to turn presence on for some or all channels without writing code

One property runs through everything below: presence is live state, not stored state. A client's occupancy, state, and event history exist only while that client stays connected, and nothing in Presence keeps a record once it disconnects. If you need a durable answer to "who belongs to this channel", that's [membership](#presence-and-membership-answer-different-questions), a separate feature.

## How presence delivers its data

When [Presence is enabled on your keyset](#turn-on-presence-without-writing-code), PubNub creates a companion channel for every channel you subscribe to. It's named after the channel with a `-pnpres` suffix: `chat.room1` gets `chat.room1-pnpres`. PubNub publishes a channel's presence events on that companion channel, over the same real-time delivery path as ordinary messages.

That shared delivery path is why presence needs no separate connection or polling loop. Subscribing with the `receivePresenceEvents` option (the exact name varies by SDK) subscribes you to the companion channel automatically. You then read presence events with the same [event listener](https://www.pubnub.com/docs/pub-sub/subscribe/event-listeners.md) you already use for messages and signals, through a dedicated `onPresence` handler.

The following is illustrative rather than a complete program. It enables `receivePresenceEvents` on a subscription and logs each event that arrives:

### JavaScript

```javascript
const channel = pubnub.channel('channel_1');
const subscription = channel.subscription({ receivePresenceEvents: true });

subscription.onPresence = (event) => console.log('Presence event:', event);

subscription.subscribe();
```

### Python

```python
subscription = pubnub.channel('channel_1').subscription(with_presence=True)

subscription.on_presence = lambda presence: print('Presence event:', presence.event, presence.uuid)

subscription.subscribe()
```

### Java

```java
Channel channel = pubnub.channel("channel_1");
Subscription subscription = channel.subscription(SubscriptionOptions.receivePresenceEvents());

subscription.setOnPresence(result ->
        System.out.println("Presence event: " + result.getEvent() + " " + result.getUuid()));

subscription.subscribe();
```

### Kotlin

```kotlin
val subscription = pubnub.channel("channel_1").subscription(SubscriptionOptions.receivePresenceEvents())

subscription.onPresence = { presence -> println("Presence event: ${presence.event} ${presence.uuid}") }

subscription.subscribe()
```

### C#

```csharp
Subscription subscription = pubnub.Channel("channel_1").Subscription(SubscriptionOptions.ReceivePresenceEvents);

subscription.onPresence += (Pubnub pn, PNPresenceEventResult e) =>
    Console.WriteLine("Presence event: " + e.Event);

subscription.Subscribe<object>();
```

### Go

```go
listener := pubnub.NewListener()

go func() {
	for presence := range listener.Presence {
		fmt.Println("Presence event:", presence.Event, presence.UUID)
	}
}()

pn.AddListener(listener)
pn.Subscribe().Channels([]string{"channel_1"}).WithPresence(true).Execute()
```

### Rust

```rust
let subscription = pubnub
    .channel("channel_1")
    .subscription(Some(vec![SubscriptionOptions::ReceivePresenceEvents]));
subscription.subscribe();

tokio::spawn(subscription.presence_stream().for_each(|presence| async move {
    println!("Presence event: {:?}", presence);
}));
```

### C-Core (legacy)

:::note New SDK available
C-Core (legacy) is still supported. If you are starting a new project, use the new [C SDK](https://www.pubnub.com/docs/sdks/c.md).
:::

```c
if (PNR_STARTED == pubnub_subscribe(pubnub, "channel_1-pnpres", NULL)) {
    pubnub_await(pubnub);
}

for (char const *event = pubnub_get(pubnub); NULL != event; event = pubnub_get(pubnub)) {
    printf("Presence event: %s\n", event);
}
```

### Swift

```swift
let subscription = pubnub.channel("channel_1").subscription(options: ReceivePresenceEvents())

subscription.onPresence = { presenceChange in
    print("Presence event: \(presenceChange)")
}

subscription.subscribe()
```

### Objective-C

```objectivec
- (void)client:(PubNub *)client didReceivePresenceEvent:(PNPresenceEventResult *)event {
    NSLog(@"Presence event: %@", event.data.presenceEvent);
}

[self.pubnub subscribeToChannels:@[@"channel_1"] withPresence:YES];
```

### Dart

```dart
final subscription = pubnub.subscribe(channels: {'channel_1'}, withPresence: true);

subscription.presence.listen((event) {
  print('Presence event: ${event.action}');
});
```

### PHP

```php
class PresenceListener extends SubscribeCallback
{
    public function presence($pubnub, $presence)
    {
        echo 'Presence event: ' . $presence->getEvent() . PHP_EOL;
    }
}

$pubnub->addListener(new PresenceListener());
$pubnub->subscribe()->channels('channel_1')->withPresence()->execute();
```

### Ruby

```ruby
callback = Pubnub::SubscribeCallback.new(
  presence: ->(envelope) { puts "Presence event: #{envelope.result}" }
)

pubnub.add_listener(callback: callback)
pubnub.subscribe(channels: ['channel_1'], with_presence: true)
```

### Unity

```csharp
listener.onPresence += (Pubnub pn, PNPresenceEventResult e) => Debug.Log("Presence event: " + e.Event);

subscription = pubnub.Channel("channel_1").Subscription(SubscriptionOptions.ReceivePresenceEvents);
subscription.Subscribe<object>();
```

### Unreal Engine

```cpp
Subscription->OnPubnubPresenceEvent.AddDynamic(this, &AMyActor::OnPresenceEventReceived);
Subscription->SubscribeAsync();

void AMyActor::OnPresenceEventReceived(FPubnubMessageData Message)
{
    UE_LOG(LogTemp, Log, TEXT("Presence event: %s, Channel: %s"), *Message.Message, *Message.Channel);
}
```

For the full subscription call and listener setup, refer to [Receive presence events](https://www.pubnub.com/docs/presence/receive-presence-events.md).

Presence identifies clients by [User ID](https://www.pubnub.com/docs/architecture/core-concepts.md#user-id), the same identity Pub/Sub, access control, and billing use. One consequence is specific to presence. If several devices connect with the same User ID, they count as one user for billing. But each device's connection and disconnection still generates its own presence events. A person who closes one tab while staying connected on another can produce a `leave` immediately followed by a `join`, even though they never went offline.

## Query who's online right now

Call `Here Now` to ask a channel, on demand, how many clients are subscribed, who they are, and what state each one has set. It's the fetch counterpart to presence events. Use it once to seed a screen, such as an online-friends list. Then rely on presence events to keep that list current instead of calling `Here Now` again.

A companion call, `Where Now`, answers the opposite question: which channels a specific User ID is currently subscribed to. It's rarely needed outside testing and troubleshooting, because most applications already know which channels a client subscribes to.

For occupancy limits, response caching, and count-only queries on high-traffic channels, refer to [Occupancy](https://www.pubnub.com/docs/presence/occupancy.md). For the calls themselves, refer to [Get online users in a channel](https://www.pubnub.com/docs/presence/get-online-users-in-channel.md) and [Get subscribed channels for a user](https://www.pubnub.com/docs/presence/get-subscribed-channels-for-user.md).

## Attach state to a subscription

Presence state is custom data, such as a mood, a game score, or a typing indicator. You attach it to a User ID on a channel while that User ID stays subscribed. Other subscribers can read it with `Here Now` or with a dedicated `Get State` call, and a `state-change` presence event fires whenever you set it.

State lives only as long as the subscription that carries it. PubNub doesn't persist presence state, and disconnecting a client clears it, so a client that reconnects has to set its state again if it still applies. That's what separates presence state from [App Context](https://www.pubnub.com/docs/data-storage/metadata/overview.md), which stores structured metadata about users and channels indefinitely regardless of connection status. Use presence state for something that's only meaningful while a client is online, and App Context for anything that needs to survive a disconnect.

For the calls that set and read state, refer to [Set and get presence state](https://www.pubnub.com/docs/presence/set-and-get-presence-state.md).

## React to arrivals and departures in real time

Beyond `state-change`, presence generates events for the rest of a client's lifecycle on a channel. `join` fires when it subscribes, `leave` when it unsubscribes, and `timeout` when it stops responding for longer than PubNub's heartbeat allows. PubNub SDKs set `presenceTimeout` to 300 seconds by default, which is how long PubNub waits without a heartbeat before marking a client offline. You can shorten that window with explicit heartbeats when your application needs faster disconnect detection than the default gives you.

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. This keeps a busy channel's presence traffic from growing in step with its occupancy. For the event payloads, the announce and interval modes, and how to tune heartbeat timing, refer to [Presence events](https://www.pubnub.com/docs/presence/presence-events.md). For the subscription call, refer to [Receive presence events](https://www.pubnub.com/docs/presence/receive-presence-events.md).

## Presence and membership answer different questions

Presence and [membership](https://www.pubnub.com/docs/architecture/core-concepts.md#membership) are easy to conflate, because both relate a User ID to a channel, but one is live and the other is stored. Presence tells you who is on a channel right now. Membership tells you who belongs to it, connected or not. Refer to [Core concepts](https://www.pubnub.com/docs/architecture/core-concepts.md#membership) for the full comparison, including how to combine both into one roster that distinguishes online members from offline ones.

## Turn on presence without writing code

Presence must be enabled on the keyset, and new keysets have it enabled by default. Beyond that switch, how much presence data you generate is a configuration choice, not a coding one. You make that choice in [Presence Management](https://www.pubnub.com/docs/presence/overview.md), under BizOps Workspace in the [Admin Portal](https://admin.pubnub.com/), rather than in your application code.

There, you choose between two starting points. Tracking selected channels only, the recommended default, keeps presence events off until you add a rule naming which channel patterns and event types to track. Tracking all channels turns every presence event on for every channel, which is simpler to reason about but can increase cost on high-traffic keysets. A rule can also set the occupancy threshold that triggers interval mode, the interval cadence, and whether a dropped TCP connection reports a `leave` instead of a `timeout`. Because these are keyset-level settings, changing them takes effect for every connected client without a client-side release.

## Presence and access control

When [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md) is enabled on your keyset:

* When [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md) is enabled, calling `Here Now` requires `read` permission on the queried channel.
* `Where Now` requires no channel-level permission when [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md) is enabled because it looks up a User ID rather than a channel.
* When [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md) is enabled, receiving presence events requires `read` permission on the channel, which also grants access to its `-pnpres` companion channel.
* When [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md) is enabled, `Get State` and `Set State` both require `read` permission on the channel.

## Next steps

* [Presence events](https://www.pubnub.com/docs/presence/presence-events.md). Event types, payloads, announce and interval modes, and heartbeat configuration.
* [Occupancy](https://www.pubnub.com/docs/presence/occupancy.md). `Here Now` in depth: limits, caching, and count-only queries.
* [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 list current subscribers and their state.
* [Set and get presence state](https://www.pubnub.com/docs/presence/set-and-get-presence-state.md). Attach and read custom state on a subscription.
* [Get subscribed channels for a user](https://www.pubnub.com/docs/presence/get-subscribed-channels-for-user.md). Call `Where Now` for a specific User ID.
* [Core concepts](https://www.pubnub.com/docs/architecture/core-concepts.md). Channels, User IDs, and membership.
* [Presence Management](https://www.pubnub.com/docs/presence/overview.md). Configure presence rules in the Admin Portal.

Last updated at: 2026-09-30T07:20:08.000Z
