---
source_url: https://www.pubnub.com/docs/sdks/javascript/api-reference/presence
title: Presence API for JavaScript SDK
updated_at: 2026-06-04T11:11:57.625Z
sdk_name: PubNub JavaScript SDK
sdk_version: 11.0.1
---

> 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 API for JavaScript SDK

PubNub JavaScript SDK, use the latest version: 11.0.1

Install:

```bash
npm install pubnub@11.0.1
```

Presence lets you track who is online or offline and store custom state information. Presence shows:

* When a user has joined or left a channel
* How many users are subscribed to a particular channel (occupancy)
* Which channels a user or device is subscribed to
* Presence state associated with these users
* To learn more about Presence as a feature, visit the [Presence overview](https://www.pubnub.com/docs/general/presence/overview).

:::note Supported and recommended asynchronous patterns
PubNub supports [Callbacks, Promises, and Async/Await](https://javascript.info/async) for asynchronous JS operations. The recommended pattern is Async/Await and all sample requests in this document are based on it. This pattern returns a status only on detecting an error. To receive the error status, you must add the [try...catch](https://javascript.info/try-catch) syntax to your code.
:::

## Receive presence events

To receive real-time presence events (join, leave, timeout, state-change) as they happen, subscribe to a channel with `receivePresenceEvents: true` and handle them in a listener. This is separate from the REST API methods below, which query presence on demand.

For more details on subscriptions and event listeners, refer to [Publish & Subscribe](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#event-listeners).

### Sample code

#### JavaScript

```javascript
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

pubnub.addListener({
  presence: (event) => {
    console.log('Presence event:', event.action, event.uuid);
    console.log('Occupancy:', event.occupancy);
    // event.action: 'join' | 'leave' | 'timeout' | 'state-change'
  },
});

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

#### React

```jsx
import React, { useState, useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function PresenceTracker() {
  const [onlineUsers, setOnlineUsers] = useState([]);
  const [occupancy, setOccupancy] = useState(0);

  useEffect(() => {
    pubnub.addListener({
      presence: (event) => {
        // event.action: 'join' | 'leave' | 'timeout' | 'interval' | 'state-change'
        if (event.action === 'join') {
          setOnlineUsers((prev) => [...prev.filter((id) => id !== event.uuid), event.uuid]);
        } else if (event.action === 'leave' || event.action === 'timeout') {
          setOnlineUsers((prev) => prev.filter((id) => id !== event.uuid));
        }
        // occupancy is present on join/leave/timeout/interval but not on state-change
        if (event.action !== 'state-change') setOccupancy(event.occupancy);
      },
    });

    const channel = pubnub.channel('my_channel');
    const subscription = channel.subscription({ receivePresenceEvents: true });
    subscription.subscribe();

    return () => {
      subscription.unsubscribe();
      pubnub.removeAllListeners();
    };
  }, []);

  return (
    <div>
      <p>Online users: {occupancy}</p>
      <ul>
        {onlineUsers.map((userId) => (
          <li key={userId}>{userId}</li>
        ))}
      </ul>
    </div>
  );
}
```

## Here now

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

This method returns information about the current state of a channel, including a list of unique user IDs (universally unique identifiers, UUIDs) currently subscribed to the channel and the total occupancy count of the channel.

:::note Cache
This method has a 3-second response cache time.
:::

### Method(s)

To call `Here Now`, you can use the following method(s) in the JavaScript SDK:

```javascript
pubnub.hereNow({
    channels: Array<string> ,
    channelGroups: Array<string> ,
    includeUUIDs: boolean ,
    includeState: boolean ,
    limit: number ,
    offset: number
}); Promise<HereNowResponse>
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channels | array<string> | Optional |  | Specifies the `channel` name to return occupancy results. You must specify either `channels` or `channelGroups`. |
| channelGroups | array<string> | Optional |  | The `channel group` for which here now information should be received. You must specify either `channels` or `channelGroups`. Wildcards are not supported. |
| includeUUIDs | boolean | Optional | `true` | Setting `uuid` to `false` disables the return of uuids. |
| includeState | boolean | Optional | `false` | Setting state to `true` enables the return of subscriber state information. |
| limit | number | Optional | `1000` | Maximum number of occupants to return per channel. Valid range: `0-1000`. Use `0` to get occupancy counts without user details. |
| offset | number | Optional |  | Zero-based starting index for pagination. Returns occupants starting from this position in the list. Must be `>= 0`. Requires `limit > 0`. Use with `limit` to paginate through large occupant lists. This parameter is only included in the request when `offset > 0`. |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. It includes necessary imports and executes methods with console logging. Use it as a reference when working with other examples in this document.
:::

###### JavaScript

#### Get a list of UUIDs subscribed to channel

```javascript
import PubNub from 'pubnub';
// Initialize PubNub with your keys
const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});
```

```javascript
// Function to get presence information for a channel
try {
  const result = await pubnub.hereNow({
    channels: ['ch1'],
    channelGroups: ['cg1'],
    includeUUIDs: true,
    includeState: true,
  });
  console.log('Here Now Result:', result);
} catch (error) {
  console.error(
    `Here Now failed with error: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

###### React

```jsx
import React, { useState, useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function ChannelOccupancy() {
  const [occupancy, setOccupancy] = useState(null);
  const [onlineUsers, setOnlineUsers] = useState([]);

  useEffect(() => {
    async function fetchPresence() {
      try {
        const result = await pubnub.hereNow({
          channels: ['my_channel'],
          includeUUIDs: true,
          includeState: true,
        });
        const channel = result.channels['my_channel'];
        setOccupancy(channel.occupancy);
        setOnlineUsers(channel.occupants.map((o) => o.uuid));
      } catch (error) {
        console.error('hereNow failed:', error);
      }
    }
    fetchPresence();
  }, []);

  return (
    <div>
      <p>Users online: {occupancy ?? '...'}</p>
      <ul>
        {onlineUsers.map((uuid) => (
          <li key={uuid}>{uuid}</li>
        ))}
      </ul>
    </div>
  );
}
```

### Response

```javascript
type hereNowResponse = {
    totalChannels: number, // totalChannels = get total of channels
    totalOccupancy: number, // totalOccupancy = get total of occupancies
    channels: object // channels = get a map with values for each channel with uuids and states for each occupant of the channel
}
```

### Other examples

#### Returning state

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

```javascript
try {
  const response = await pubnub.hereNow({
    channels: ['my_channel'],
    includeState: true,
  });
  console.log('hereNow response:', response);
} catch (error) {
  console.error(
    `hereNow failed with error: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

##### Example response

```javascript
// Example of Status
{
    "error": false,
    "operation": "PNHereNowOperation",
    "statusCode": 200
}

// Example of Response
{
    "totalChannels": 1,
    "totalOccupancy": 3,
    "channels": {
        "my_channel": {
            "occupants": [
                {
                    "uuid": "User 1"
                },
                {
                    "state": {
                        "age": 18
                    },
                    "uuid": "User 2"
                },
                {
                    "state": {
                        "age": 24
                    },
                    "uuid": "User 3"
                }
            ],
            "name": "my_channel",
            "occupancy": 3
        }
    }
}
```

#### Return occupancy only

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

You can return only the `occupancy` information for a single channel by specifying the channel and setting `includeUUIDs` and `includeState` to `false`:

```javascript
try {
  const response = await pubnub.hereNow({
    channels: ['my_channel'],
    includeUUIDs: false,
  });
  console.log('hereNow response:', response);
} catch (error) {
  console.error(
    `hereNow failed with error: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

##### Example response

```javascript
// Example of Status
{
    "error": false,
    "operation": "PNHereNowOperation",
    "statusCode": 200
}

// Example of Response
{
    "totalChannels": 1,
    "totalOccupancy": 3,
    "channels": {
        "my_channel": {
            "occupants": [],
            "name": "my_channel",
            "occupancy": 3
        }
    }
}
```

#### Channel group usage

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

```javascript
try {
  const response = await pubnub.hereNow({
    channelGroups: ['my_channel_group'],
  });
  console.log('hereNow response:', response);
} catch (error) {
  console.error(
    `hereNow failed with error: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

##### Example response

```javascript
// Example of Status
{
    "error": false,
    "operation": "PNHereNowOperation",
    "statusCode": 200
}

// Example of Response
{
    "totalChannels": 2,
    "totalOccupancy": 3,
    "channels": {
        "my_channel_1": {
            "occupants": [
                {
                    "state": null,
                    "uuid": "User1"
                },
                {
                    "state": null,
                    "uuid": "User3"
                }
            ],
            "name": "my_channel_1",
            "occupancy": 2
        },
        "my_channel_2": {
            "occupants": [
                {
                    "state": null,
                    "uuid": "User2"
                }
            ],
            "name": "my_channel_2",
            "occupancy": 1
        }
    }
}
```

#### Sample code with promises

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

```javascript
pubnub
  .hereNow({
    channels: ['ch1'],
    channelGroups: ['cg1'],
    includeUUIDs: true,
    includeState: true,
  })
  .then((response) => {
    console.log(response);
  })
  .catch((error) => {
    console.log(error);
  });
```

## Where now

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

This method returns the list of channels a UUID is subscribed to.

:::note Timeout events
If the app restarts (or the page refreshes) within the heartbeat window, no timeout event is generated.
:::

### Method(s)

To call `whereNow`, you can use the following method(s) in the JavaScript SDK:

```javascript
pubnub.whereNow({
    uuid: string
}): Promise<WhereNowResponse>
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: stringDefault: `current uuid` | Specifies the `uuid` to return channel list for. |

### Sample code

You simply need to define the `uuid` to be used to send the data to as in the example below.

#### JavaScript

#### Get a list of channels a UUID is subscribed to

```javascript
try {
  const response = await pubnub.whereNow({
    uuid: 'uuid',
  });
  console.log('State set successfully:', response);
} catch (error) {
  console.error(
    `State set failed: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

#### React

```jsx
import React, { useState, useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function UserChannels() {
  const [channels, setChannels] = useState([]);

  useEffect(() => {
    async function fetchChannels() {
      try {
        const result = await pubnub.whereNow({ uuid: pubnub.userId });
        setChannels(result.channels);
      } catch (error) {
        console.error('whereNow failed:', error);
      }
    }
    fetchChannels();
  }, []);

  return (
    <div>
      <p>Subscribed channels:</p>
      <ul>
        {channels.map((ch) => (
          <li key={ch}>{ch}</li>
        ))}
      </ul>
    </div>
  );
}
```

### Response

```javascript
// Example of Status
{
    error: false,
    operation: "PNWhereNowOperation",
    statusCode: 200
}

// Example of Response
{
    "channels": ["ch1", "ch2"]
}
```

## User state

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

Clients can set a dynamic custom state (score, game state, location) for their users on one or more channels and store it on a channel as long as the user stays subscribed.

The state is not persisted, and when the client disconnects, the state data is lost. For more information, refer to [Presence State](https://www.pubnub.com/docs/general/presence/presence-state).

### Method(s)

#### Set state

```javascript
pubnub.setState({
    channels: Array<string> ,
    channelGroups: Array<string> ,
    state: any
}): Promise<SetStateResponse>;
```

| Parameter | Description |
| --- | --- |
| `channels`Type: Array | Either `channels` or `channelGroups` should be provided, Specifies the `channels` to set the state. |
| `channelGroups`Type: Array | Either `channels` or `channelGroups` should be provided, Specifies the Channel Group to set the state |
| `state`Type: any | JSON object of key/value pairs with supported data-types of int, float and string. Nesting of key/values is not permitted and key names beginning with prefix `pn` are reserved. If the state parameter is undefined, the current state for the specified `uuid` will be returned. If a specified key already exists for the `uuid` it will be over-written with the new value. Key values can be deleted by setting the particular value to `null`. |

#### Get state

```javascript
pubnub.getState({
    uuid: string,
    channels: Array<string>, 
    channelGroups: Array<string>
}): Promise<GetStateResponse>; 
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `current uuid` | The subscriber `uuid` to get the current state. |
| `channels`Type: ArrayDefault: n/a | Either `channels` or `channelGroups` should be provided, Specifies the `channels` to get the state. |
| `channelGroups`Type: ArrayDefault: n/a | Either `channels` or `channelGroups` should be provided, Specifies the Channel Group to get the state. |

### Sample code

#### JavaScript

#### Set state

```javascript
try {
  const response = await pubnub.setState({
    state: { status: 'online' },
    channels: ['ch1'],
    channelGroups: ['cg1'],
  });
  console.log('State set successfully:', response);
} catch (error) {
  console.error(
    `State set failed: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

#### Get state

```javascript
try {
  const response = await pubnub.getState({
    uuid: 'uuid',
    channels: ['ch1'],
    channelGroups: ['cg1'],
  });
  console.log('State retrieved successfully:', response);
} catch (error) {
  console.error(
    `State retrieval failed: ${error}.${
      (error as PubNubError).status ? ` Additional information: ${(error as PubNubError).status}` : ''
    }`,
  );
}
```

#### React

#### Set state

```jsx
import React, { useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function UserWithPresenceState() {
  useEffect(() => {
    async function setPresenceState() {
      try {
        const response = await pubnub.setState({
          state: { status: 'online' },
          channels: ['my_channel'],
        });
        console.log('State set successfully:', response);
      } catch (error) {
        console.error('setState failed:', error);
      }
    }
    setPresenceState();
  }, []);

  return <div>User with presence state</div>;
}
```

#### Get state

```jsx
import React, { useState, useEffect } from 'react';
import PubNub from 'pubnub';

const pubnub = new PubNub({
  publishKey: 'YOUR_PUBLISH_KEY',
  subscribeKey: 'YOUR_SUBSCRIBE_KEY',
  userId: 'YOUR_USER_ID',
});

function UserState() {
  const [presenceState, setPresenceState] = useState(null);

  useEffect(() => {
    async function fetchState() {
      try {
        const result = await pubnub.getState({
          uuid: pubnub.userId,
          channels: ['my_channel'],
        });
        setPresenceState(result.channels);
      } catch (error) {
        console.error('getState failed:', error);
      }
    }
    fetchState();
  }, []);

  return <pre>{JSON.stringify(presenceState, null, 2)}</pre>;
}
```

### Response

#### Set state

```javascript
// Example of Status
{
    error: false,
    operation: "PNSetStateOperation",
    statusCode: 200
}

// Example of Response
{
    state: {
        me: 'typing'
    }
}
```

#### Get state

```javascript
// Example of Status
{
    error: false,
    operation: "PNGetStateOperation",
    statusCode: 200
}

// Example of Response
{
    channels: {
        ch1: {
            me: 'typing'
        }
    }
}
```