Tracking user presence
Presence lets you track the online and offline status of users and devices in real time and store custom state information. When you have Presence enabled in the Admin Portal, PubNub automatically creates equivalents of all channels that monitor and collect all presence events.
For more information, refer to User Presence.
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.
Get user occupancy
Use the hereNow method to get information about the current state of users in a channel. The call returns a list of unique users currently subscribed to the channel.
- JavaScript
- Java
- Swift
- Objective-C
- Unity
1pubnub.hereNow({
2 channels: ['ch-1'],
3 includeUUIDs: true,
4 includeState: true,
5}, (status, response) => {
6 // handle status, response
7});
1pubnub.hereNow()
2 .channels(Arrays.asList("ch-1"))
3 .includeUUIDs(true)
4 .includeState(true)
5 .async(result -> {
6 result.onSuccess(res -> {
7 Map<String, PNHereNowChannelData> channelsMap = res.getChannels();
8 for (String channel : channelsMap.keySet()) {
9 PNHereNowChannelData channelData = channelsMap.get(channel);
10 System.out.println("Channel: " + channelData.getChannelName());
11 System.out.println("Occupants: " + channelData.getOccupancy());
12 for (PNHereNowOccupantData occupant : channelData.getOccupants()) {
13 System.out.println("\tUserID: " + occupant.getUuid());
14 System.out.println("\tState: " + occupant.getState());
15 }
show all 20 lines1pubnub.hereNow(on: ["ch-1"], also: true) { result in
2 switch result {
3 case let .success(response):
4 print("Successful HereNow Response: \(response)")
5 case let .failure(error):
6 print("Failed HereNow Response: \(error.localizedDescription)")
7 }
8}
1[self.client hereNowForChannel: @"ch-1" withVerbosity:PNHereNowUUID
2 completion:^(PNPresenceChannelHereNowResult *result,
3 PNErrorStatus *status) {
4 if (!status) {
5 /**
6 Handle downloaded presence information using:
7 result.data.uuids - list of uuids.
8 result.data.occupancy - total number of active subscribers.
9 */
10 }
11 else {
12 }
13}];
1pubnub.HereNow()
2 .Channels(new List<string>(){
3 "ch-1"
4 })
5 .IncludeState(true)
6 .IncludeUUIDs(true)
7 .Async((result, status) => {
8 if (status.Error) {
9 Debug.Log(string.Format("HereNow Error: {0} {1} {2}", status.StatusCode, status.ErrorData, status.Category));
10 } else {
11 Debug.Log(string.Format("Channels: {0} {1}", result.TotalChannels, result.TotalOccupancy));
12 }
13 Debug.Log(status.Error);
14 });
User state
Users can set dynamic custom state on one or more channels. This custom state persists on a channel as long as the user stays subscribed to that channel. Some examples of custom states are to add your score, game state, or location in an application if it changes frequently.
Use the setState method to set dynamic state for a user on channels. A state is an object of key/value pairs with any arbitrary data, as long as the data is of type int, float, or string. When you set or update the state, PubNub fires a state-change event to other users on the channel.
- JavaScript
- Java
- Swift
- Objective-C
- Unity
1pubnub.setState({
2 state: {
3 mood: 'grumpy',
4 },
5 channels: ['main'],
6}, (status, response) => {
7 // handle state setting response
8});
1JsonObject state = new JsonObject();
2state.addProperty("mood", "grumpy");
3
4pubNub.setPresenceState()
5 .state(state)
6 .channels(Arrays.asList("main"))
7 .async(result -> { /* check result */ });
1pubnub.setPresence(
2 state: ["New": "State"],
3 on: ["main"]
4) { result in
5 switch result {
6 case let .success(response):
7 print("Successful Set State Response: \(response)")
8 case let .failure(error):
9 print("Failed Set State Response: \(error.localizedDescription)")
10 }
11}
1[self.client setState: @{@"Key": @"Value"} forUUID:self.client.uuid onChannel: @"main"
2 withCompletion:^(PNClientStateUpdateStatus *status) {
3
4 if (!status.isError) {
5
6 // Client state successfully modified on specified channel.
7 }
8 else {
9
10 /**
11 Handle client state modification error. Check 'category' property
12 to find out possible reason because of which request did fail.
13 Review 'errorData' property (which has PNErrorData data type) of status
14 object to get additional information about issue.
15
show all 19 lines1Dictionary<string, object> state = new Dictionary<string, object>();
2state.Add("mood", "grumpy");
3
4pubnub.SetPresenceState()
5 .Channels(new List<string> (){"main"})
6 .State(state)
7 .Async((result, status) => {
8 if(status.Error){
9 Debug.Log (string.Format("In Example, SetPresenceState Error: {0} {1} {2}", status.StatusCode, status.ErrorData, status.Category));
10 } else {
11 Debug.Log (string.Format("DateTime {0}, In Example SetPresenceState, result:", DateTime.UtcNow));
12 if(result != null){
13 if(result.StateByChannels!= null){
14 foreach (KeyValuePair<string, object> key in dict){
15 Debug.Log(string.Format("Channel:{0}, State:{1}", key.Key, pubnub.JsonLibrary.SerializeToJsonString(key.Value)));
show all 20 linesYou can get state data for any client on a given channel(s) or channel group(s) user the Get State API. This is useful to get the state of other clients based on their User ID.
- JavaScripts
- Java
- Swift
- Objective-C
- Unity
1pubnub.getState(
2 {
3 uuid: "john-doe",
4 channels: ["main"],
5 channelGroups: ["my_channel_group"]
6 },
7 function (status, response) {
8 // handle status, response
9 }
10);
1pubnub.getPresenceState()
2 .channels(Arrays.asList("main"))
3 .channelGroups(Arrays.asList("my_channel_group"))
4 .uuid("anotherClientUserID")
5 .async(result -> { /* check result */ });
1pubnub.getPresenceState(
2 for: "john-doe",
3 on: ["main"],
4 and: ["my_channel_group"]
5) { result in
6 switch result {
7 case let .success(response):
8 print("Successful Get State Response: \(response)")
9
10 case let .failure(error):
11 print("Failed Get State Response: \(error.localizedDescription)")
12 }
13}
1 [self.pubnub stateForUUID:@"john-doe" onChannel:@"chats.room1"
2 withCompletion:^(PNChannelClientStateResult *result, PNErrorStatus *status) {
3
4 if (!status) {
5
6 }
7 else {
8
9 }
10}];
1pubnub.GetPresenceState()
2 .UUID("john-doe")
3 .Channels(new List<string> (){"main"})
4 .ChannelGroups(new List<string> (){"my_channel_group"})
5 .Async((result, status) => {
6
7 if(status.Error){
8 Debug.Log (string.Format(" GetPresenceState Error: {0} {1} {2}", status.StatusCode, status.ErrorData, status.Category));
9 } else {
10 Debug.Log (string.Format("DateTime {0}, In Example GetPresenceState, result:", DateTime.UtcNow));
11 if(result != null){
12 if(result.StateByChannels!= null){
13 foreach (KeyValuePair<string, object> key in dict){
14 Debug.Log(string.Format("Channel:{0}, State:{1}", key.Key, pubnub.JsonLibrary.SerializeToJsonString(key.Value)));
15 }
show all 19 linesFor more details on working with user state, refer to Setting Custom Presence State.
Presence events
PubNub triggers presence events as users come online or go offline from the application. Clients can receive these events directly, or you can use webhooks on a server to keep a user's online/offline status up to date. Use these events to keep track of users coming and going and the total occupancy of the channel.
| 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 320 seconds (just over 5 minutes). |
state-change | Fires anytime the user's state is changed using the state API (function signature varies by SDK). |
interval | Fires to provide an occupancy count. The default setting for the Presence Interval property is 10 seconds, which is configurable on your Admin Portal's Presence add-on panel. |
Join event:
1{
2 "channel": "room-1",
3 "subscription": null,
4 "actualChannel": null,
5 "subscribedChannel": "room-1-pnpres",
6 "action": "join",
7 "timetoken": "15119466699655811",
8 "occupancy": 2,
9 "uuid": "user1",
10 "timestamp": 1511946669
11}
Leave event:
1{
2 "channel": "room-1",
3 "subscription": null,
4 "actualChannel": null,
5 "subscribedChannel": "room-1-pnpres",
6 "action": "leave",
7 "timetoken": "15119446002445794",
8 "occupancy": 1,
9 "uuid": "user1",
10 "timestamp": 1511944600
11}
Timeout event:
1{
2 "channel": "room-1",
3 "subscription": null,
4 "actualChannel": null,
5 "subscribedChannel": "room-1-pnpres",
6 "action": "timeout",
7 "timetoken": "15119519897494311",
8 "occupancy": 3,
9 "uuid": "user1",
10 "timestamp": 1511951989
11}
User state change event:
1{
2 "channel": "room-1",
3 "subscription": null,
4 "actualChannel": null,
5 "subscribedChannel": "room-1-pnpres",
6 "action": "state-change",
7 "state": {
8 "mood": "grumpy"
9 },
10 "timetoken": "15119477895378127",
11 "occupancy": 5,
12 "uuid": "user1",
13 "timestamp": 1511947789
14}
Interval event:
1{
2 "channel": "room-1",
3 "subscription": null,
4 "actualChannel": null,
5 "subscribedChannel": "room-1-pnpres",
6 "action": "interval",
7 "timetoken": "15119477895378127",
8 "occupancy": 2,
9 "timestamp": 1511947739
10}