---
source_url: https://www.pubnub.com/docs/general/channels/subscribe
title: Subscriptions
updated_at: 2026-05-22T11:05:01.396Z
---

> 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


# Subscriptions

As PubNub allows you to have hundreds or even thousands of subscriptions, it's vital to understand how to manage them efficiently.

##### Understanding the subscribe loop

When you call any subscribe method in the PubNub SDK, an internal mechanism called the subscribe loop is automatically initiated. This is a core part of PubNub's real-time functionality:

* The subscribe loop runs internally within the SDK - you don't need to manually start or maintain it.
* It maintains a persistent connection to PubNub's servers, [automatically handling reconnections](https://www.pubnub.com/docs/general/setup/connection-management#reconnection-policy) if the network drops.
* The loop continuously receives and processes incoming messages, delivering them to your event handlers or callbacks.
* The loop is optimized for minimal battery and network usage while maintaining real-time responsiveness.

When you unsubscribe or call methods like `unsubscribeAll()`, the SDK automatically stops the subscribe loop for those channels.

Some lower-level SDKs expose [direct control of the subscribe loop](https://www.pubnub.com/docs/sdks/c-core/api-reference/misc#start-a-callback-subscribe-loop), but these are for advanced use cases only and aren't needed for typical implementations.

Read on to understand what subscriptions and subscription sets are, and how to manage multiple [channels](https://www.pubnub.com/docs/general/channels/overview) with [channel groups](#channel-groups), [wildcards](#wildcard-subscribe), and [Message Filters](#message-filters).

Now that you know the subscribe loop runs automatically, see how subscription objects use this loop to receive events efficiently.

:::tip Receiving messages
To receive and handle incoming messages, signals, and events, you first [add an event listener](https://www.pubnub.com/docs/general/messages/receive#add-an-event-handler). If you're new to PubNub, review how to set up [your account](https://www.pubnub.com/docs/general/setup/account-setup).
:::

## Subscription types

The basic types of subscriptions are entity-scoped subscriptions and subscription sets. Within the PubNub SDKs, they are represented as `Subscription` and `SubscriptionSet` (although naming may vary between SDKs). For more information, refer to [Entities](https://www.pubnub.com/docs/general/entities).

Entity-scoped subscriptions build on PubNub’s Entity framework, which provides object‑oriented abstractions for channels, users, and groups. For concepts, see [Entities](https://www.pubnub.com/docs/general/entities).

:::warning Entity-enabled SDKs
Some PubNub SDKs support entities today, and others will add support over time. Refer to your SDK's [API documentation](https://www.pubnub.com/docs/sdks) for details.
:::

##### How we did subscriptions in the past

For a long time, the approach towards subscriptions at PubNub was to have a global list of subscriptions and event handlers created directly using the `pubnub` object. This led to event listeners being responsible for handling events for all channels and groups to which the PubNub client was subscribed.

```javascript
const pubnub = new PubNub({
    /* initiation arguments */
});

pubnub.addListener({
    status: async (statusEvent) => {
        if (statusEvent.category === "PNConnectedCategory") {
            try {
                await pubnub.setState({
                    state: {
                        some: "state",
                    },
                });
            } catch (status) {
                // handle setState error
            }
        }
    },
    message: (messageEvent) => {
      if (messageEvent.channel === "ch1")
        // handle message from ch1
      else if (messageEvent.channel === "ch2")
        // handle message from ch2
      else if (messageEvent.channel === "ch3")
        // handle message from ch3
    },
    presence: (presenceEvent) => {
        // handle presence
      if (presenceEvent.channel === "ch1")
        // handle presence from ch1
      else if (presenceEvent.channel === "ch2")
        // handle presence from ch2
      else if (presenceEvent.channel === "ch3")
        // handle presence from ch3
    },
});

pubnub.subscribe({
    channels: ["ch1", "ch2", "ch3"],
});
```

As a result, the code within these handlers often became bloated due to the need to include many conditional blocks to differentiate events by their type and source. Since handlers could only be attached to the PubNub client, it became mandatory for users to pass references to this client object wherever event handling was needed, which significantly complicated code architecture. Additionally, removing handlers was a manual effort.

The new approach allows you to create separate subscriptions for each channel and handle its logic within the scope of the subscription:

```javascript
const channel1 = pubnub.channel('ch1');
const channel2 = pubnub.channel('ch2');
const channel3 = pubnub.channel('ch3');

const subscription1 = channel1.subscription({ receivePresenceEvents: true });
const subscription2 = channel2.subscription();
const subscription3 = channel3.subscription();

subscription1.addListener({
    // handle message from ch1
    message: (m) => { console.log('Received message', m) },
    // handle message from ch1
    presence: (p) => { console.log('Presence event', p) },
});

subscription2.addListener({
    // handle message from ch2
    message: (m) => { console.log('Received message', m) }
});

subscription3.addListener({
    // handle message from ch3
    message: (m) => { console.log('Received message', m) }
});

subscription1.subscribe();
subscription2.subscribe();
subscription3.subscribe();
```

Consider a simple application that displays stock prices. When users first launch the app, they see popular stocks, but after logging in, they can view their favorite stocks as well.

**With the previous approach:**

1. On app launch: Subscribe to `commonStock` channel.
2. On user login: Subscribe to `favoriteStock` channel (now subscribed to both)
3. On user logout: Must determine which channels to unsubscribe from (in this case `favoriteStock`)

This requires maintaining global knowledge of which channels should be active at any point:

```javascript
// App launch
pubnub.subscribe({ channels: ["commonStock"] });

// User login
pubnub.subscribe({ channels: ["favoriteStock"] });

// User logout - must know which channel to unsubscribe from
pubnub.unsubscribe({ channels: ["favoriteStock"] });
```

**With the new subscription approach:**

1. On app launch: Create and subscribe to `commonStock` channel.
2. On user login: Create new subscriptions for both channels.
3. On user logout: Simply unsubscribe the login-related subscriptions.

Each screen or component only needs to manage its own subscriptions:

```javascript
// App launch
const commonSub1 = pubnub.channel("commonStock").subscription();
commonSub1.subscribe();

// When user logs in
const commonSub2 = pubnub.channel("commonStock").subscription();
const favoriteSub = pubnub.channel("favoriteStock").subscription();
// Create a set if you want to handle both with the same listeners
const loggedInSubs = pubnub.subscriptionSet({
  channels: ["commonStock", "favoriteStock"]
});
loggedInSubs.subscribe();

// When user logs out
loggedInSubs.unsubscribe();
// No need to track which channels should remain active
```

This approach eliminates the need to maintain a global view of channel subscriptions, making your code more modular.

| Subscription type | When to use | Sample usage | Benefits |
| --- | --- | --- | --- |
| `Subscription` | When you want to introduce more granularity and flexibility to the way you handle particular events. | If you want to handle the same message differently on two (or however many) channels, you can create a separate subscription for each channel and attach different event listeners. | Create multiple subscription objects that can be activated/deactivated without affecting others, Event handlers tied to specific subscriptions eliminate complex conditional logic, Multiple subscriptions are multiplexed over a single connection |
| `SubscriptionSet` | When you want to introduce common functionality to a number of events. | If you want to have a common logic for specific updates (for example, handling status updates), you can create a subscription set with all channels where user's presence is to be monitored and attach a single event listener. | Manage multiple channels as a group without tracking global state, Apply the same event handling logic across multiple channels, Each component can manage its own subscription set |

Both `Subscription` and `SubscriptionSet` objects have intuitive interfaces for subscription-related operations (like switching between the active and inactive states) and working with listeners. On top of that, you can create subscription sets from existing entity-scoped subscriptions if you decide you need to handle a bunch of subscriptions similarly.

##### Sample usage

Let's consider the following example. Edward, a developer, created three subscription entities: `channel_1`, `channel_2`, `channel_3`, and a subscription set `all_channels` composed of all three channels.

The programmer of the application wants to handle the messages that are sent to each of the channels differently but have a common logic for handling events when users join any of the channels. A user with the ID of `alex_1` joins the three channels and sends a `Hello world!` message.

* Messages sent to `channel_1` are printed out to the console.
* Messages sent to `channel_2` are forwarded to a third-party system for sentiment analysis.
* Messages sent to `channel_3` stop the application if the message payload is `stop`.

By creating separate entity-scoped subscription objects for each channel, the programmer added the same `Message` event listener type and provided different handle logic for each channel.

For the common functionality, the programmer created a subscription set with all channels and added a single `Presence` event listener which shares the handling logic across the subscription set.

### Subscription options

You can customize the real-time stream with these options.

Available options include:

| Subscription option | Description |
| --- | --- |
| `filter` | Allows you to specify arbitrary filtering for events coming through the subscription. |
| `receivePresenceEvents` | Allows you to decide whether to receive [presence](https://www.pubnub.com/docs/general/presence/overview) updates. |

For more information on how to use the subscription options in each SDK, refer to each SDK's Subscribe section of the API documentation, for example, in [JavaScript](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe).

### Create subscriptions

Each SDK has dedicated methods to create subscriptions and subscription sets. For more information on managing subscriptions, refer to each SDK's Subscribe section of the API documentation, for example, [JavaScript](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe).

### Receiving events on subscriptions

#### Using on[Event] handlers

You can assign functions directly to event-specific properties on the subscription object. This approach provides a clean, straightforward way to handle specific events.

```javascript
const channelSubscription = pubnub.channel('channel_name').subscription();
channelSubscription.subscribe();

// Handle messages
channelSubscription.onMessage = function(message) {
  console.log('Received message:', message);
};

// Handle presence events
channelSubscription.onPresence = function(presenceEvent) {
  console.log('Presence event:', presenceEvent);
};

// Other handlers are available for signals, objects, files, and message actions
```

This method allows for clear, direct assignment of handlers to specific event types and is particularly useful when you want to add or change handlers dynamically.

For more information on how to use the `on[Event]` syntax, refer to each SDK's API documentation, for example, [JavaScript](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#add-listeners).

#### Using addListener() method

This approach is more similar to the previous SDK versions and lets you define all event handlers in a single call. This can be more familiar if you're upgrading from earlier versions.

```javascript
channelSubscription.addListener({
  // Handle messages
  message: (message) => {
    console.log('Received message:', message);
  },
  
  // Handle presence events
  presence: (presenceEvent) => {
    console.log('Presence event:', presenceEvent);
  },
  
  // Other event handlers for signals, objects, files, message actions
});
```

The `addListener()` method is convenient when setting up multiple event handlers at once and may be more familiar to developers who have used previous versions of PubNub SDKs.

For more information on how to use the `addListener()` method, refer to each SDK's API documentation, for example, [JavaScript](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#add-listeners).

Both approaches work the same. Choose the style that fits your app and team. Syntax may vary between SDKs. See your [SDK docs](https://www.pubnub.com/docs/sdks) for details.

## Subscribe to channels

After you add a listener, subscribe to one or more channels. Subscribing opens a connection to the PubNub platform and triggers a status event. The connection stays open while at least one channel is subscribed. In typical cases, users receive messages in under 30 ms worldwide.

:::note Default subscribe timeout
The default timeout is 310 seconds (about 5 minutes) for requests related to subscribed channels. You can reduce this limit in your client configuration by setting the `subscribeTimeout` parameter.
:::

:::note Subscription with Presence
To receive Presence events, you [subscribe with Presence](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe) and have Presence enabled on your keyset. Make sure you configure Presence to track [Presence-related events](https://www.pubnub.com/docs/general/presence/overview#configuration) for all or selected channels (through [Presence Management rules](https://www.pubnub.com/docs/bizops-workspace/presence-management)).
:::

:::tip Registering listeners before subscribing
Register your event listeners before calling `subscribe()`. Presence events like `join` are triggered shortly after the subscription is established, and registering listeners first ensures no events are missed. For details on presence event types, the `-pnpres` channel mechanism, and delivery, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

The client can subscribe to several channels over a single open connection. Subscribe on app load. Stay subscribed as users navigate to keep receiving messages. Or subscribe and unsubscribe as users move through the app.

### Configuration

To subscribe a single client to multiple channels, enable Stream Controller on your keyset in the [Admin Portal](https://admin.pubnub.com/) to use these options:

* [Channel Multiplexing](https://www.pubnub.com/docs/general/channels/subscribe#channel-multiplexing) — subscribing to multiple channels in a single API call
* [Wildcard Subscriptions](https://www.pubnub.com/docs/general/channels/subscribe#wildcard-subscribe) — subscribing to groups of channels that share a common naming pattern, like `news.*`
* [Channel Groups](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) — creating named groups of channels and then subscribing to the group as a whole

Contrary to [other features](https://www.pubnub.com/docs/portal/keysets#feature-configuration) that you must specifically enable, Stream Controller is active by default on all new keysets.

![Stream Controller in Admin Portal](https://www.pubnub.com/assets/images/stream-controller-695a7435b6dd31a07dbf26905339485a.png)

| Option | Description |
| --- | --- |
| **Enable Wildcard Subscribe** | An option that lets you subscribe to groups of channels with a shared naming pattern, like `*.chat.*` |
| **Channel group limit** | The maximum number of channels you can add to channel groups. The default limit of 1,000 channels applies to all new keysets and can be modified if you have a paid account — you can then either lower the limit or increase it up to 2,000 channels. |

### Signal channel subscribe

To receive Signals, you don't need a different subscription to the channel, but you do need a separate `signal` event listener as mentioned in the [Adding a Listener](https://www.pubnub.com/docs/general/messages/receive) section.

### Channel multiplexing

Subscribing to multiple channels from a single client is called multiplexing. You can subscribe to one or more channels by creating many individual subscription objects or subscription sets. You can also create individual subscriptions and create a subscription set from them when their number increases.

Multiplexing allows each client to subscribe to a combination of channels of their choosing and change that selection at any time.

Use multiplexing for a small set of channels. We recommend 10–50 channels per subscribe request. Use fewer if your app is large. For larger sets, prefer [channel groups](#channel-groups).

:::note Channel ID length impact
Longer channel IDs increase the combined HTTP payload size. Long IDs can increase the size of the multiplex request and may exceed the Uniform Resource Identifier (URI) length [limit](https://www.pubnub.com/docs/general/setup/limits#general-api-limits) of 32 KiB.
:::

You can subscribe to one or more channels in a single request or you can spread those requests out in your application's flow. For example, a client might subscribe to `chats.room1` now and then later subscribe to `chats.room2`. Doing so will simply add `chats.room2` to the current list of channels that have already been subscribed as if you subscribed to them at the same time.

For example, below is how you would subscribe to a channel `chats.room1` when the user of your app enter their first chat room.

###### JavaScript

```javascript
const channel = pubnub.channel('chats.room1');
channel.subscription().subscribe();
```

###### Swift

```swift
let subscription1 = pubnub.channel("chants_room1").subscription()
```

###### Objective-C

```objectivec
[self.pubnub subscribeToChannels: @[@"chats.room1"] withPresence:NO];
```

###### Java

```java
pubnub.subscribe().channels(Arrays.asList("chats.room1")).execute();
```

###### C#

```csharp
Subscription subscription1 = pubnub.Channel("chats_room1").Subscription()

subscription1.Subscribe<object>()
```

###### Python

```python
channel = pubnub.channel("chats.room1")
t1_subscription = channel.subscription()
t1_subscription.subscribe()
```

The user continues to use your application, and then decides to enter another chat room, `chats.room2`.

###### JavaScript

```javascript
// create a subscription from a channel entity
const channel = pubnub.channel('chats.room1')
const subscription1 = channel.subscription({ receivePresenceEvents: true });

// create a subscription from a channel entity
const channelGroup = pubnub.channel('chats.room2')
const subscription2 = channel.subscription();

const subscriptionSet = subscription1.addSubscription(subscription2);
subscriptionSet.subscribe();
```

###### Swift

```swift
// Create a subscription from a channel entity
let subscription1 = pubnub.channel("chats.room1").subscription()

// Create a subscription from a channel group entity
let subscription2 = pubnub.channelGroup("chats.room2").subscription()

// Create a subscription set from individual entities
let subscriptionSet = SubscriptionSet(subscriptions: [subscription1, subscription2])
```

###### Objective-C

```objectivec
[self.pubnub subscribeToChannels: @[@"chats.room2"] withPresence:NO];
```

###### Java

```java
pubnub.subscribe().channels(Arrays.asList("chats.room2")).execute();
```

###### C#

```csharp
Subscription subscription1 = pubnub.Channel("chats_room2").Subscription()

subscription1.Subscribe<object>()
```

###### Python

```python
channel2 = pubnub.channel("chats.room2")
t2_subscription = channel.subscription()
t2_subscription.subscribe()
```

The result is that the user is now subscribed to both chat room channels.

You can also leverage [Channel Groups](#channel-groups) and [Wildcard Subscribe](#wildcard-subscribe). Below you'll be briefly introduced to these two alternative subscription management features.

:::note Enable Stream Controller
Multiplexing is available by default, regardless of your [Admin Portal](https://admin.pubnub.com) configuration. To use Wildcard Subscribe and Channel Groups, enable the **Stream Controller** add-on on your keyset in the Admin Portal.
:::

### Channel groups

A channel group is a named list of channels. Use channel groups to listen to many channels with a single subscribe. By default, each individual client can subscribe to a maximum of 10 channel groups for a total of up to 1,000 channels.

:::note Modify limits for channels in channel groups
The default limit of 1,000 channels in channel groups per keyset applies to all new keysets created in the [Admin Portal](https://admin.pubnub.com/). If you have a paid account, you can change the **Channel group limit** under the **Stream Controller** section for your keyset to lower the default or increase it up to 2,000 channels.
:::

#### Subscribe vs. publish to channel groups

You can only subscribe to a channel group; you cannot publish to it. Use your server to add and remove channels in the group. Clients stay in sync automatically.

Your clients may not need to listen to that many channels, but channel groups make it possible for your server to manage the channels that the client is subscribed to by adding and removing channels on behalf of the clients.

To use a channel group, instead of multiplexing, there is just one additional step - add channels to a channel group. This also creates the channel group if it doesn't already exist. This should be performed by your server for security and ease of management.

##### JavaScript

```javascript
pubnub.channelGroups.addChannels({
    channels: ["chats.room1", "chats.room2", "alerts.system"]
    channelGroup: "cg_user123"
  },
  function(status) {
      console.log(status);
  }
);
```

##### Swift

```swift
pubnub.add(
  channels: ["chats.room1", "chats.room2", "alerts.system"],
  to: "cg_user123"
) { result in
  switch result {
    case let .success(response):
      print("succeeded: \(response)")

    case let .failure(error):
      print("failed: \(error.localizedDescription)")
  }
}
```

##### Objective-C

```objectivec
[self.pubnub addChannels: @[@"chats.room1", @"chats.room2", @"alerts.system"]
              toGroup:"cg_user123" withCompletion:^(PNAcknowledgmentStatus *status) {
    // handle success/error
}];
```

##### Java

```java
pubnub.addChannelsToChannelGroup()
  .channelGroup("cg_user123")
  .channels(Arrays.asList("chats.room1", "chats.room2", "alerts.system"))
  .async(result -> { /* check result */ });
```

##### C#

```csharp
pubnub.AddChannelsToChannelGroup()
  .ChannelGroup("cg_user123")
  .Channels(new string[] {"chats.room1", "chats.room2", "alerts.system"})
  .Execute(new PNChannelGroupsAddChannelResultExt((result, status) => {
      // handle success/error
    }
  ));
```

##### Python

```python
pubnub.add_channel_to_channel_group()\
  .channels(["chats.room1", "chats.room2", "alerts.system"])\
  .channel_group("cg_user123")\
  .sync()
```

The client subscribes to the channel group.

###### JavaScript

```javascript
const channelGroup = pubnub.channelGroup('cg_user123');
channelGroup.subscribe();
```

###### Swift

```swift
let subscription = pubnub.channelGroup("cg_user123").subscription()

subscription.subscribe()
```

###### Objective-C

```objectivec
[self.pubnub subscribeToChannelGroups:@["cg_user123"] withPresence:true];
```

###### Java

```java
pubnub.subscribe()
  .channelGroups(Arrays.asList("cg_user123"))
  .withPresence()
  .execute();
```

###### C#

```csharp
Subscription subscription1 = pubnub.ChannelGroups("cg_user123").Subscription(SubscriptionOptions.ReceivePresenceEvents)

subscription1.Subscribe<object>()
```

###### Python

```python
channel_group = pubnub.channel_group("cg_user123")
t3_subscription = channel_group.subscription()
t3_subscription.subscribe()
```

When messages are published to any of the channels in this channel group, it will be received in the message handler of the client's listener. The channel group subscribes can also be enabled with `withPresence` parameter to start receiving presence events for all the channels in the Channel Group.

:::note Subscription with Presence
To receive Presence events, you [subscribe with Presence](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe) and have Presence enabled on your keyset. Make sure you configure Presence to track [Presence-related events](https://www.pubnub.com/docs/general/presence/overview#configuration) for all or selected channels (through [Presence Management rules](https://www.pubnub.com/docs/bizops-workspace/presence-management)).
:::

Decide whether you need presence events. You can separate channels into two channel groups: `cg_presence_user123` (channels with presence tracking) and `cg_user123` (channels without presence tracking). This can all be done on the client app.

Additionally, with Channel Groups your server can force a client to unsubscribe from a particular channel just by removing that channel from the channel group that the client is subscribed to.

Your server can also force a client to unsubscribe from a channel. Remove that channel from the channel group, and the client unsubscribes.

#### Channel group names

Channel groups can be shared just like channels. For example, you may want to create a channel group called `cg_sports`. Multiple clients can subscribe to this shared channel group and your server can add new channels related to sports and all the clients will automatically be subscribed to those new channels.

And there is no requirement to prefix the name with `cg_`. It's only a convention that makes it easy to recognize Channel Groups. Feel free to use a naming convention that works best for your requirements and design style.

:::note Channel Group Names
Channel Group names have the same rules as Channel names with one exception: you cannot use a period in the name. This means that wildcard features do not apply to Channel Groups.
:::

Just because you're using Channel Groups does not mean you can't also subscribe to individual channels. Sometimes it may be convenient to subscribe to a particular channel directly while also subscribing to a separate Channel Group. You can specify channels and channel groups in the same subscribe call or make individual subscribe calls. And channel groups can be multiplexed, too.

###### Extend channel groups with presence, access control, and lifecycle awareness

When you subscribe to a channel group with presence enabled, you receive aggregated presence events for all member channels through a single subscription. To secure these operations, grant `read` permission for subscribing and listing channels, or `manage` permission for server-side group management. A channel group is created automatically when you add the first channel and removed explicitly through the delete API. Each client can subscribe to up to 10 groups containing a total of 1,000 channels by default (configurable to 2,000 on paid plans). See [Presence Basics](https://www.pubnub.com/docs/general/presence/overview), [Access Manager permissions](https://www.pubnub.com/docs/general/security/access-control#channel-groups), and [API Limits](https://www.pubnub.com/docs/general/setup/limits#subscribe) for details.

### Wildcard subscribe

Wildcard Subscribe `channelName.*` can be used to subscribe to a hierarchical list of channels. It's similar to Channel Group in that you can subscribe to lots of channels with a single name declaration. For example, you specify a wildcard channel pattern like `sports.*`, and your app will subscribe to all channel names that match that pattern: `sports.cricket`, `sports.lacrosse`. This list can be virtually infinite in number with some limitations described in the next section.

#### JavaScript

```javascript
const channel = pubnub.channel("alerts.*");
channel.subscription().subscribe();
```

#### Swift

```swift
let subscription1 = pubnub.channel("alerts.*").subscription()
```

#### Objective-C

```objectivec
[self.pubnub subscribeToChannels: @[@"alerts.*", @"chats.team1.*"] withPresence:YES];
```

#### Java

```java
pubnub.subscribe()
  .channels(Arrays.asList("alerts.*", "chats.team1.*")
  .withPresence())
  .execute();
```

#### C#

```csharp
SubscriptionSet subscriptionSet = pubnub.Subscription(
    new string[] {"alerts.*", "chats.team1.*"},
    SubscriptionOptions.ReceivePresenceEvents
)
```

#### Python

```python
subscription_set1 = pubnub.subscription_set(channels=["alerts.*", "chats.team1.*"])
subscription_set1.subscribe(with_presence = True)
```

#### Wildcard subscribe rules

* At most two dots (three levels): `a.*` and `a.b.*` are valid; `a.b.c.*` is not.
* Patterns must end with `.*`; `a.*.c` is not valid.
* You cannot publish to a wildcard pattern.

### Message filters

:::note Prerequisite
Enable Stream Controller on your keyset before using subscribe filters.
:::

Subscribe filters perform server-side filtering so you receive only messages that match your criteria.

Key capabilities include:

* **Message payload filtering** - Filter based on any field in the message content using `data.*` syntax
* **Metadata filtering** - Filter based on metadata attached during publishing using `meta.*` syntax
* **Advanced operations** - Support for pattern matching (LIKE, CONTAINS), arithmetic (modulo, comparisons), array/object access, and complex compound expressions
* **Real-time performance** - Filters are applied server-side with minimal latency impact

Subscribe filters can access two main data sources:

* `data.fieldName` - Any field within the published message payload
* `meta.fieldName` - Any metadata field attached via the `meta` parameter during publishing

:::warning Publisher and channel filtering
Filter by publisher ID, channel names, or message types by including these properties in message metadata during publishing. Envelope fields do not support direct filtering.
:::

#### Basic filter examples

```javascript
// Message payload filtering
data.type == "alert"                          // Filter by message type
data.priority != "low"                        // Exclude low priority
data.user["role"] == "admin"                  // Filter by user role in payload

// Metadata filtering  
meta.region == "San Francisco"                      // Geographic filtering
meta.level > 5                                // Numeric thresholds
meta.category LIKE "news*"                    // Pattern matching

// Combined filtering
(meta.priority == "high") && (data.text CONTAINS "urgent")
```

#### Setting filter expressions

##### JavaScript

```javascript
// Initialize PubNub
var pubnub = new PubNub({
  publishKey: "myPublishKey",
  subscribeKey: "mySubscribeKey",
  userId: "myUserId"
});

// Set filter expression for metadata filtering
pubnub.setFilterExpression('meta.priority == "high"');

// Set filter expression for payload filtering  
pubnub.setFilterExpression('data.type == "alert"');

// Set complex filter expression
pubnub.setFilterExpression('(meta.priority == "high") && (data.user["role"] == "admin")');
```

##### Swift

```swift
// Set filter during configuration initialization
let config = PubNubConfiguration(
    publishKey: "myPublishKey",
    subscribeKey: "mySubscribeKey",
    userId: "myUserId",
    filterExpression: "meta.priority == \"high\""
)
let pubnub = PubNub(configuration: config)

// For different filter expressions, create new configurations
let payloadConfig = PubNubConfiguration(
    publishKey: "myPublishKey",
    subscribeKey: "mySubscribeKey", 
    userId: "myUserId",
    filterExpression: "data.type == \"alert\""
)
let payloadPubNub = PubNub(configuration: payloadConfig)
```

##### Objective-C

```objectivec
// Set filter via configuration (filters cannot be changed after initialization)
PNConfiguration *pnconfig = [PNConfiguration configurationWithPublishKey:@"myPublishKey"
                                                            subscribeKey:@"mySubscribeKey"];
pnconfig.uuid = @"myUserId";

// Set metadata filter during configuration
pnconfig.filterExpression = @"meta.priority == \"high\"";
PubNub *pubnub = [PubNub clientWithConfiguration:pnconfig];

// For different filters, create new configuration
PNConfiguration *payloadConfig = [PNConfiguration configurationWithPublishKey:@"myPublishKey"
                                                                subscribeKey:@"mySubscribeKey"];
payloadConfig.uuid = @"myUserId";
payloadConfig.filterExpression = @"data.type == \"alert\"";
PubNub *payloadPubNub = [PubNub clientWithConfiguration:payloadConfig];
```

##### Java

```java
PNConfiguration.Builder configBuilder = PNConfiguration.builder(new UserId("yourUserId"), "yourSubscribeKey");
configBuilder.publishKey("myPublishKey");

// Set filter via configuration
configBuilder.setFilterExpression("meta.priority == \"high\"");

PubNub pubNub = PubNub.create(configBuilder.build());
```

##### C#

```csharp
PNConfiguration pnconfig = new PNConfiguration();
pnconfig.PublishKey = "myPublishKey";
pnconfig.SubscribeKey = "mySubscribeKey";
pnconfig.UserId = UserId;

// Set filter via configuration
pnconfig.FilterExpression = "meta.priority == \"high\"";

Pubnub pubnub = new Pubnub(pnconfig);
```

##### Python

```python
pnconfig = PNConfiguration()
pnconfig.publish_key = "myPublishKey"
pnconfig.subscribe_key = "mySubscribeKey"
pnconfig.user_id = user_id

# Set filter via configuration
pnconfig.filter_expression = 'meta.priority == "high"'

pubnub = PubNub(pnconfig)
```

#### Filterable message properties

Subscribe filters can access the following message components:

| Supported | Property | Filter access | Examples | Notes |
| --- | --- | --- | --- | --- |
| Yes | Message payload | `data.*` | `data.text`, `data.type`, `data.user["role"]`, `data.tags[0]` | Any field within the published message content |
| Yes | Message metadata | `meta.*` | `meta.priority`, `meta.level`, `meta.user["role"]`, `meta.flags[0]` | Metadata attached via the [metaparameter](https://www.pubnub.com/docs/general/messages/publish#publish-with-message-filters) |
| No | Publisher user ID | n/a | n/a | Include in metadata as `meta.publisher` if needed |
| No | Channel name | n/a | n/a | Include in metadata as `meta.channel` if needed |
| No | Timetoken | n/a | n/a | Not accessible to filter expressions |
| No | Message type (envelope field) | n/a | n/a | Include in payload as `data.type` or in metadata as `meta.type` |

### Advanced access patterns

These examples show common ways to access arrays and objects, apply arithmetic, match patterns, and combine conditions in subscribe filter expressions.

* Array access: `meta.tags[0] == "urgent"`, `data.recipients[1] LIKE "*@domain.com"`
* Object access: `meta.user["role"] == "admin"`, `data.config["enabled"] == "true"`
* Arithmetic: `meta.userId % 10 == 0`, `data.score > (meta.threshold * 1.1)`
* Pattern matching: `meta.category LIKE "news*"`, `data.text CONTAINS "urgent"`
* Compound logic: `(meta.priority == "high" || meta.priority == "critical") && data.type == "alert"`

For comprehensive documentation, syntax reference, and advanced examples, see [Subscribe Filter Details](https://www.pubnub.com/docs/general/channels/subscribe-filters).

#### Common use cases

Use these filters to route content, run analytics, and handle IoT data.

##### Content-based routing

```javascript
// High-priority alerts from specific regions
(meta.priority == "high" || meta.priority == "critical") && meta.region == "San Francisco"

// User role-based messaging
data.user["role"] == "admin" && data.action != "routine"
```

##### Real-time analytics filtering

```javascript
// Sample 10% of events for analytics
meta.eventId % 10 == 0 && data.category == "conversion"

// Error monitoring for production systems
data.severity == "error" && meta.environment == "production"
```

##### IoT data stream filtering

```javascript
// Temperature alerts only
data.sensor["type"] == "temperature" && data.value > meta.thresholds["critical"]

// Device health monitoring  
meta.device["status"] != "maintenance" && data.battery < 20
```

#### Advanced filter capabilities

Use these patterns to access arrays and objects, perform arithmetic, and handle booleans.

##### Array and object access

```javascript
meta.permissions[0] == "admin"                // Array element access
meta.user["department"] == "engineering"      // Object property access  
data.recipients[1] LIKE "*@company.com"       // Pattern matching on arrays
meta.config["alerts"]["email"] == "enabled"  // Single-level nesting only
```

##### Arithmetic operations

```javascript
meta.userId % 100 == 0                        // Modulo sampling (1%)
data.score > (meta.baseline + 10)             // Calculated thresholds
meta.attempts < (meta.maxRetries - 1)         // Range validation
```

##### Boolean value handling

```javascript
meta.enabled == "true"                        // Boolean as string (recommended)
meta.active != "false"                        // Boolean inequality check
meta.flag == 1                                // Numeric boolean (1=true, 0=false)
```

:::note Boolean literals not supported
Use string comparison (`meta.field == "true"`) instead of boolean literals (`meta.field == true`). JSON boolean values are stored as strings and must be compared as such.
:::

For complete syntax reference, advanced examples, performance guidelines, and troubleshooting information, see the comprehensive [Subscribe Filter Details](https://www.pubnub.com/docs/general/channels/subscribe-filters) documentation.

### Unsubscribe from channels

Unsubscribe to stop receiving messages. You can target one or many channels.

#### JavaScript

```javascript
// create a subscription from a channel entity
const channel = pubnub.channel('channel_1')
const subscription1 = channel.subscription({ receivePresenceEvents: true });

// create a subscription set with multiple channels
const subscriptionSet1 = pubnub.subscriptionSet({ channels: ['ch1', 'ch2'] });

subscription1.subscribe();
subscriptionSet1.subscribe();

subscription1.unsubscribe();
subscriptionSet1.unsubscribe();
```

#### Swift

```swift
let subscriptionSet = pubnub.subscription(
  entities: [
    pubnub.channel("channel"),
    pubnub.channelGroup("channelGroup"),
    pubnub.userMetadata("userMetadataIdentifier")
  ],
  options: ReceivePresenceEvents()
)

let subscription1 = pubnub.channel("channelName").subscription() 

subscriptionSet.subscribe()
subscription1.subscribe()

subscriptionSet.unsubscribe()
subscription1.unsubscribe()
```

#### Java

```java
Channel myChannel = pubnub.channel("ch-1");

SubscriptionOptions options = SubscriptionOptions.receivePresenceEvents();

Subscription subscription = myChannel.subscription(options);

subscription.subscribe();
subscription.unsubscribe();
```

#### Unity

```csharp
Subscription subscription1 = pubnub.Channel("channelName").Subscription()

SubscriptionSet subscriptionSet = pubnub.Subscription(
    new string[] {"channel1", "channel2"},
    new string[] {"channel_group_1", "channel_group_2"},
    SubscriptionOptions.ReceivePresenceEvents
)

subscription1.Subscribe<object>()
subscriptionSet.Subscribe<object>()

subscription1.Unsubscribe<object>()
subscriptionSet.Unsubscribe<object>()
```

### Unsubscribe from all channels

Use this method to unsubscribe from all channels.

#### JavaScript

```javascript
// create a subscription set with multiple channels
const subscriptionSet1 = pubnub.subscriptionSet({ channels: ['ch1', 'ch2'] });
subscriptionSet1.subscribe();

// create a subscription from a channel entity
const channelGroup = pubnub.channelGroup('channelGroup_1')
const subscription1 = channelGroup.subscription({ receivePresenceEvents: true });
subscription1.subscribe();

pubnub.unsubscribeAll();
```

#### Swift

```swift
let subscriptionSet = pubnub.subscription(
  entities: [
    pubnub.channel("channel"),
    pubnub.channelGroup("channelGroup"),
    pubnub.userMetadata("userMetadataIdentifier")
  ],
  options: ReceivePresenceEvents()
)

let subscription1 = pubnub.channel("channelName").subscription() 

subscriptionSet.subscribe()
subscription1.subscribe()

pubnub.unsubscribeAll()
```

#### Java

```java
pubnub.unsubscribeAll();
```

#### Unity

```csharp
Subscription subscription1 = pubnub.Channel("channelName").Subscription()

SubscriptionSet subscriptionSet = pubnub.Subscription(
    new string[] {"channel1", "channel2"},
    new string[] {"channel_group_1", "channel_group_2"},
    SubscriptionOptions.ReceivePresenceEvents
)

subscription1.Subscribe<object>()
subscriptionSet.Subscribe<object>()

pubnub.UnsubscribeAll<object>()
```

### Deprecation of previous subscription APIs

As PubNub introduces the new entity-based subscription architecture across its SDKs, the previous global subscription APIs (such as `pubnub.subscribe()` and `pubnub.unsubscribe()`) are being marked as deprecated. However, to ensure a smooth transition for developers, each SDK supports a long end-of-life (EOL) period.

The deprecation timeline varies by SDK. For example, in the JavaScript SDK, the "old" `pubnub.subscribe()` and `pubnub.unsubscribe()` methods have been marked as deprecated but will continue to function for the documented EOL period.

For specific information about the deprecation schedule for your SDK, please refer to the documented EOL period in your SDK's documentation, typically found toward the bottom of the SDK feature list.

## Status events

When channels are subscribed, connections are disconnected, reconnected or when connection errors are encountered, status events are generated and clients can receive those events in the listener's `status` listener.

:::note Listener
Add the status listener to the `pubnub` object, not to a particular subscription or subscription set.
:::

Most SDKs provide an operation and category as part of a status event. The supported categories may vary with each language and platform, and some SDKs may have a more robust architecture than others. The differences will be noted as necessary.

### Handle status events

The event listeners are briefly mentioned in [Receive Messages](https://www.pubnub.com/docs/general/messages/receive). Compared to other event types, status events are more focused on connection status and subscribe request errors.

#### JavaScript

Because the browser can detect when the connection is lost and restored, the JavaScript SDK (when running in a browser) has two additional events that allow you to explicitly handle those scenarios: `PNNetworkDownCategory` and `PNNetworkUpCategory`. Other environments do not support this real-time network status behavior.

The following data can be extracted from a JavaScript SDK status event.

```javascript
// add a status listener
pubnub.addListener({
    status: (s) => {
      console.log('Status', s.category),
       }
});

// available data:
//     var affectedChannelGroups = event.affectedChannelGroups;
//     var affectedChannels = event.affectedChannels;
//     var category = event.category;
//     var operation = event.operation;
//     var lastTimetoken = event.lastTimetoken;
//     var currentTimetoken = event.currentTimetoken;
//     var subscribedChannels = event.subscribedChannels;
```

For more details on handling Status Events, visit the [JavaScript SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/javascript/status-events).

#### Swift

The iOS-based SDKs have the most robust status event architecture. There are many more event types that allow you to more explicitly handle each scenario. The following is just a subset of the events which focus on connection and subscribe scenarios.

```swift
pubnub.onConnectionStateChange = { newStatus in
   print("Connection Status: \(newStatus)")   
}
```

For more details on handling Status Events, visit the [Swift SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/swift/status-events).

#### Objective-C

The iOS SDKs include more status event types. Use them to handle each scenario more directly. Below is a subset focused on connection and subscribe.

All status events are passed into the `didReceiveStatus` delegate. Use operations and categories to decide how to handle each case.

```objectivec
[self.pubnub addListener:self];

- (void)client:(PubNub *)pubnub didReceiveStatus:(PNStatus *)event {
    NSString *operation = event.operation;
    NSString *category = event.category;
}
```

For more details on handling Status Events, visit the [Objective-C SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/objective-c/status-events).

#### Java

```java
pubnub.addListener(new StatusListener() {
  @Override
  public void status(PubNub pubnub, PNStatus event) {
        String operation = event.getOperation();
        String category = event.getCategory();
  }
});
```

For more details on handling Status Events, visit the [Java SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/java/status-events).

#### C#

```csharp
SubscribeCallbackExt eventListener = new SubscribeCallbackExt(
 delegate (Pubnub pn, PNStatus e) {
  Console.WriteLine("Status event");
 }
);

pubnub.AddListener(eventListener)
```

For more details on handling Status Events, visit the [C# SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/c-sharp/status-events).

#### Python

```python
class PrintListener(SubscribeListener):
    def status(self, pubnub, status):
        print(f'Status:\n{status.__dict__}')

    def message(self, pubnub, message):
        pass

    def presence(self, pubnub, presence):
        pass

listener = PrintListener()
pubnub.add_listener(listener)
```

For more details on handling Status Events, visit the [Python SDK Status Events documentation page](https://www.pubnub.com/docs/sdks/python/status-events).

## Terms in this document

* **Entity** - A subscribable object within a PubNub SDK that allows you to perform context-specific operations.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **Signal** - A non-persistent message limited to 64 bytes designed for high-volume usecases where the the most recent data is relevant, like GPS location updates.
