Presence Events
PubNub triggers presence events as users come online or go offline from the application.
Subscription with Presence
You must create a subscription with Presence enabled to receive Presence events. For more information, refer to each SDK's Publish and Subscribe documentation.
Clients can receive these events directly or use webhooks to keep a user's online/offline status up to date. Use these events to keep track of active/inactive users and the total occupancy of the channel.
Presence webhooks
PubNub can invoke a REST endpoint on your server when presence events occur. For more information, refer to Events & Actions.
Presence Event Types
There are five main types of presence events:
Events | Description |
---|---|
join | Fires when a user subscribes to a channel. |
leave | Fires when a user unsubscribes from a channel. |
timeout | Fires when a connection to a channel is lost and the subscriber hasn't been seen in 300 seconds. |
state-change | Fires anytime the user's state is changed. |
interval | Fires in interval mode to provide an occupancy count and optionally include delta changes. |
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.
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.
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) |
- JavaScript
- Swift
- Objective-C
- Java
- C#
- Python
- Kotlin
subscription.addListener({
presence: function (p) {
const action = p.action; // Can be join, leave, timeout, state-change, or interval
const channelName = p.channel; // Channel to which the message belongs
const occupancy = p.occupancy; // Number of users subscribed to the channel
const state = p.state; // User state
const channelGroup = p.subscription; // Channel group or wildcard subscription match, if any
const publishTime = p.timestamp; // Publish timetoken
const timetoken = p.timetoken; // Current timetoken
const uuid = p.uuid; // UUIDs of users who are subscribed to the channel
}
}
subscription.onPresence = { presenceChange in
for action in presenceChange.actions {
switch action {
case let .join(uuids):
print("The following list of occupants joined at \(presenceChange.timetoken): \(uuids)")
case let .leave(uuids):
print("The following list of occupants left at \(presenceChange.timetoken): \(uuids)")
case let .timeout(uuids):
print("The following list of occupants timed-out at \(presenceChange.timetoken): \(uuids)")
case let .stateChange(uuid, state):
print("\(uuid) changed their presence state to \(state) at \(presenceChange.timetoken)")
}
}
}
- (void)pubnub:(PubNub *)pubnub didReceivePresenceEvent:(PNPresenceEventResult *)event {
NSString *action = event.data.presenceEvent;
NSString *channel = event.data.channel;
NSString *occupantUserId = event.data.presence.uuid;
NSString *eventTimetoken = event.data.presence.timetoken;
NSInteger *occupancy = event.data.presence.occupancy;
NSDictionary *state = event.data.presence.state;
}
@Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
String action = presence.getEvent();
String channel = presence.getChannel();
String occupantUserId = presence.getUuid();
String eventTimetoken = presence.getTimetoken();
String occupancy = presence.getOccupancy();
Object state = presence.getState();
}
Subscription subscription1 = pubnub.Channel("channelName").Subscription()
SubscribeCallbackExt eventListener = new SubscribeCallbackExt(
delegate (Pubnub pn, PNPresenceEventResult e) {
string action = event.GetEvent();
string channel = event.GetChannel();
string occupantUserId = event.GetPublisher();
long eventTimetoken = event.GetTimetoken();
int occupancy = event.GetOccupancy();
object state = event.GetUserMetaData();
}
);
subscription1.AddListener(subscribeCallback)
show all 16 lines# Add event-specific listeners
# without closure
def on_presence(listener):
def presence_callback(presence):
print(f"\033[0;32mPresence received on: {listener}: \t{presence.uuid} {presence.event}s "
f"{presence.subscription or presence.channel}\033[0m")
return presence_callback
subscription.on_presence = on_presence
# add generic listener
class PrintListener(SubscribeCallback):
show all 20 linessubscription.addListener(object : EventListener {
override fun presence(pubnub: PubNub, presence: PNPresenceEventResult) {
// Handle presence updates
println("Presence: ${presence.uuid} - ${presence.event}")
}
})
Subscribe to Presence Channel
Once you've created the subscription with the receivePresenceEvents
option (name may vary across SDKs,) added presence listeners, call subscribe()
to receive presence events. Your client will now start receiving presence events in real time as users join and leave channels.
When you enable the receivePresenceEvents
option, the SDK automatically subscribes you to presence channels. These channels are sister channels where presence events are published by PubNub. 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
.
- JavaScript
- Swift
- Objective-C
- Java
- C#
- Python
- Kotlin
// 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();
// create a subscription from a channel entity
let subscription1 = pubnub.channel("channelName").subscription(options: ReceivePresenceEvents())
// subscribe and start receiving real-time updates
subscription1.subscribe()
[self.pubnub subscribeToChannels: @[@"chats.room1", @"chats.room2"] withPresence:NO];
pubnub.subscribe()
.channels(Arrays.asList("chats.room1", "chats.room2"))
.withPresence().execute();
SubscriptionSet subscriptionSet = pubnub.Subscription(
new string[] {"chats.room1", "chats.room2"},
SubscriptionOptions.ReceivePresenceEvents
)
subscription_set1 = pubnub.subscription_set(channels=["chats.room1", "chats.room2"])
subscription_set1.subscribe(with_presence = True)
// 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.
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.
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.
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.
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.
- Join
- Leave
- timeout
- State Change
{
"action": "join",
"channel": "chats.room1",
"subscribedChannel": "chats.room1-pnpres",
"timetoken": "15119466699655811",
"occupancy": 2,
"uuid": "user123",
"timestamp": 1511946669
}
{
"action": "leave",
"channel": "chats.room1",
"subscribedChannel": "chats.room1-pnpres",
"timetoken": "15119466699655811",
"occupancy": 2,
"uuid": "user123",
"timestamp": 1511946669
}
{
"action": "timeout",
"channel": "chats.room1",
"subscribedChannel": "chats.room1-pnpres",
"timetoken": "15119466699655811",
"occupancy": 2,
"uuid": "user123",
"timestamp": 1511946669
}
{
"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 goes into interval mode. In this mode, the join
, leave
, timeout
events are replaced by an interval
event which is sent every few seconds with the total occupancy on the channel. The Interval setting is also configurable for the settings page.
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. 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.
{
"action": "interval",
"channel": "chats.megachat",
"occupancy": 27,
"join": ["user123","user88"],
"leave": ["user20", "user11", "user14"],
"timeout": ["user42"],
"subscribedChannel": "chats.megachat-pnpres",
"timestamp": 1511947739,
"timetoken": "15119477396210903"
}
If a Presence Delta payload exceeds 32KB, the here_now_refresh
flag indicates that you should use the Here Now API if you wish to retrieve the list of client User IDs that may have triggered a join, leave or timeout since the last interval.