---
source_url: https://www.pubnub.com/docs/sdks/asyncio/api-reference/publish-and-subscribe
title: Publish/Subscribe API for Python-Asyncio SDK
updated_at: 2026-05-29T11:10:03.808Z
sdk_name: PubNub Python Asyncio SDK
---

> 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


# Publish/Subscribe API for Python-Asyncio SDK

PubNub Python Asyncio SDK

Install:

```bash
pip install pubnub
```

PubNub delivers messages worldwide in less than 30 ms. Send a message to one recipient or broadcast to thousands of subscribers.

For higher-level conceptual details on publishing and subscribing, refer to [Connection Management](https://www.pubnub.com/docs/general/setup/connection-management) and to [Publish Messages](https://www.pubnub.com/docs/general/messages/publish).

:::note ObjectNode
The new Jackson parser does not recognize JSONObject. Please use ObjectNode instead.
:::

## Publish

`publish()` sends a message to all subscribers of a channel. PubNub replicates the message across the network and delivers it to all subscribed clients on that channel.

### Prerequisites and limitations

* Initialize PubNub with the `publish_key`.
* You don't need to subscribe to publish to a channel.
* You can't publish to multiple channels at the same time.

### Security

Secure messages with TLS/SSL by setting `ssl` to `True` during initialization. You can also encrypt messages.

### Message data

The message can contain any JSON‑serializable data (objects, arrays, integers, strings). Avoid special Python classes or functions. Strings can include any UTF‑8 characters.

:::warning Don't JSON serialize
Don't JSON serialize `message` and `meta` when sending signals, messages, or files. Serialization is automatic. Pass full objects and let PubNub handle it.
:::

### Size

The maximum message size is 32 KiB. This includes the escaped character count and the channel name. Aim for under 1,800 bytes for optimal performance.

If your message exceeds the limit, you'll receive a `Message Too Large` error. For details, see [Message size limits](https://www.pubnub.com/docs/general/messages/publish#message-size-limit).

:::tip Need larger messages?
Our platform is optimized for payloads up to 32 KiB. PubNub supports larger messages, but increasing the limit requires a verification of compatibility with your use case.
Talk to [our team](https://www.pubnub.com/company/contact-sales/) to discuss increasing the message size limit for your use case.
:::

### Publish rate

You can publish as fast as bandwidth allows. There is a soft throughput [limit](https://www.pubnub.com/docs/general/setup/limits) because messages may drop if subscribers can't keep up.

For example, publishing 200 messages at once may cause the first 100 to drop if a subscriber hasn't received any yet. The in‑memory queue stores only 100 messages.

### Custom message type

You can optionally provide the `custom_message_type` parameter to add your business-specific label or category to the message, for example `text`, `action`, or `poll`.

### Best practices

* Publish to a channel serially (not concurrently).
* Verify a success return code (for example, `[1,"Sent","136074940..."]`).
* Publish the next message only after a success return code.
* On failure (`[0,"blah","<timetoken>"]`), retry.
* Keep the in‑memory queue under 100 messages to avoid drops.
* Throttle bursts to meet latency needs (for example, no more than 5 messages per second).

### Method(s)

To `Publish a message` you can use the following method(s) in the Python-asyncio SDK:

```python
pubnub.publish() \
    .channel(String) \
    .message(Object) \
    .should_store(Boolean) \
    .meta(Dictionary) \
    .use_post(Boolean)
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel | String | Yes |  | Destination of `message` (channel ID). |
| message | Object | Yes |  | The payload. |
| should_store | Boolean | Optional | `account default` | Store in history |
| meta | Object | Optional | `None` | Meta data object which can be used with the filtering ability. |

### Sample code

#### Publish a message to a channel

:::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.
:::

```python
import asyncio
import os
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub_asyncio import PubNubAsyncio
from pubnub.exceptions import PubNubException

async def publish_message(pubnub: PubNubAsyncio):
    try:
        # Publish a message to a channel
        envelope = await pubnub.publish() \
            .channel("my_channel") \
            .message({'name': 'Alex', 'online': True}) \
            .future()
        print(f"Publish timetoken: {envelope.result.timetoken}")
    except PubNubException as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    # Configuration for PubNub instance
    pn_config = PNConfiguration()
    pn_config.subscribe_key = os.getenv('SUBSCRIBE_KEY', 'demo')
    pn_config.publish_key = os.getenv('PUBLISH_KEY', 'demo')
    pn_config.user_id = "my_custom_user_id"

    pubnub = PubNubAsyncio(pn_config)

    try:
        loop.run_until_complete(publish_message(pubnub))
    finally:
        loop.run_until_complete(pubnub.stop())
        loop.close()
```

:::note Subscribe to the channel
Before running the above publish example, either using the [Debug Console](https://www.pubnub.com/docs/console/) or in a separate script running in a separate terminal window, [subscribe to the same channel](#subscribe) that is being published to.
:::

### Returns

The `publish()` operation returns a `PNPublishResult` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| timetoken | `Int` | an `int` representation of the timetoken when the message was published |

### Other examples

#### Publish with metadata

```python
envelope = await pubnub.publish()\
    .channel("my_channel")\
    .message(["hello", "there"])\
    .meta({'name': 'Alex'})\
    .future()

# handle publish result, status always present, result if successful
# envelope.status.is_error() to see if error happened
```

## Fire

The fire endpoint allows the client to send a message to Functions Event Handlers and [Illuminate](https://www.pubnub.com/docs/illuminate/business-objects/external-data-sources). These messages will go directly to any Event Handlers registered on the channel that you fire to and will trigger their execution. The content of the fired request will be available for processing within the Event Handler. The message sent via `fire()` isn't replicated, and so won't be received by any subscribers to the channel. The message is also not stored in history.

### Method(s)

To `Fire a message` you can use the following method(s) in the Python-asyncio SDK:

```python
pubnub.fire() \
    .channel(String) \
    .message(Object) \
    .meta(Object) \
    .use_post(Boolean)
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: StringDefault: n/a | Destination of `message` (channel ID). |
| `message` *Type: ObjectDefault: n/a | The payload. |
| `use_post`Type: BooleanDefault: `False` | Use POST to publish. |
| `meta`Type: ObjectDefault: `None` | Meta data object which can be used with the filtering ability. |

### Sample code

#### Fire a message to a channel

```python
envelope = await pubnub.fire().channel('my_channel').message('hello there').use_post(True).future()
print('fire timetoken: %d' % envelope.result.timetoken)
```

## Signal

The `signal()` function sends a signal to all subscribers of a channel.

By default, signals are limited to a message payload size of `64` bytes. This limit applies only to the payload, and not to the URI or headers. If you require a larger payload size, please [contact support](https://www.pubnub.com/docs/mailto:support@pubnub.com).

### Method(s)

To `Signal a message` you can use the following method(s) in the Python-asyncio SDK:

```python
pubnub.signal() \
    .message(Object) \
    .channel(String)
```

| Parameter | Description |
| --- | --- |
| `message` *Type: Object | The payload. |
| `channel` *Type: String | Destination of `message` (channel ID). |

### Sample code

#### Signal a message to a channel

```python
envelope = await pubnub.signal() \
    .channel('some_channel') \
    .message('foo') \
    .future()
```

### Response

| Field | Type | Description |
| --- | --- | --- |
| timetoken | `int` | An `int` representation of the timetoken when Signal was sent. |

## Subscribe

The subscribe function creates an open TCP socket to PubNub and begins listening for messages and events on a specified entity or set of entities. To subscribe successfully, you must configure the appropriate `subscribeKey` at [initialization](https://www.pubnub.com/docs/sdks/python/api-reference/configuration).

:::tip Conceptual overview
For more general information about subscriptions, refer to [Subscriptions](https://www.pubnub.com/docs/general/channels/subscribe).
:::

Entities are [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen) that provide access to their encapsulated APIs. You can subscribe using the PubNub client object or directly on a specific entity:

* [ChannelRepresentation](#create-channels)
* [ChannelGroupRepresentation](#create-channel-groups)
* [UserMetadataRepresentation](#create-user-metadata)
* [ChannelMetadataRepresentation](#create-channel-metadata)

A newly subscribed client receives messages after the `subscribe()` call completes. You can configure [automatic retries](https://www.pubnub.com/docs/sdks/asyncio/api-reference/configuration#configuration) to attempt to reconnect automatically and retrieve any available messages if a client gets disconnected.

### Subscription scope

Subscription objects provide an interface to attach listeners for various real-time update types. Your app receives messages and events via those event listeners. Two types of subscriptions are available:

* [Subscription](#create-a-subscription), created from an entity with a scope of only that entity (for example, a particular channel)
* [SubscriptionSet](#create-a-subscription-set), created from the PubNub client with a global scope (for example, all subscriptions created on a single `pubnub` object ). A subscription set can have one or more subscriptions.

The event listener is a single point through which your app receives all the messages, signals, and events in the entities you subscribed to. For information on adding event listeners, refer to [Event listeners](#event-listeners).

### Create a subscription

An entity-level `Subscription` allows you to receive messages and events for only that entity for which it was created. Using multiple entity-level `Subscription`s is useful for handling various message/event types differently in each channel.

```python
# entity-based, local-scoped
subscription = pubnub.channel(f'{channel}').subscription(timetoken: Optional[int] = None, region: Optional[str] = None, with_presence: bool = False)
```

| Parameter | Description |
| --- | --- |
| `timetoken`Type: `int` | Timetoken from which to return any available cached messages. Message retrieval with timetoken is not guaranteed and should only be considered a best-effort service. If the value is not a 17-digit number, the provided value will be ignored. |
| `region`Type: String | The region the message was published in. |
| `with_presence`Type: `bool` | Whether presence updates for `userId`s should be delivered through the listener streams. 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). |

### Create a subscription set

A client-level `SubscriptionSet` allows you to receive messages and events for all entities. A single `SubscriptionSet` is useful for similarly handling various message/event types in each channel.

```python
# client-based, general-scoped
subscription_set = pubnub.subscription_set(subscriptions: List[PubNubSubscription])
```

| Parameter | Description |
| --- | --- |
| `subscriptions` *Type: `List[PubNubSubscription]` | Channels/Channel group subscriptions. |

### Method(s)

`Subscription` and `SubscriptionSet` use the same `subscribe()` method.

#### Subscribe

To subscribe, you can use the following method in the Python SDK:

```python
subscription.subscribe()
```

##### Sample code

```python
# single channel subscription
channel = pubnub.channel(f'{channel}')
t1_subscription = channel.subscription()
t1_subscription.subscribe()

# multiple channel subscription
channel_1 = pubnub.channel(channel).subscription()
channel_2 = pubnub.channel(f'{channel}.2').subscription(with_presence=True)
channel_x = pubnub.channel(f'{channel}.*').subscription(with_presence=True)

group = pubnub.channel_group('group-test').subscription()

subscription_set = pubnub.subscription_set([channel_1, channel_2, channel_x, group])

set_subscription = subscription_set.subscribe()
```

##### Returns

The `subscribe()` method doesn't have a return value.

## Entities

Entities are subscribable objects for which you can receive real-time updates (messages, events, etc).

* [PubNubChannel](#create-channels)
* [PubNubChannelGroup](#create-channel-groups)
* [PubNubUserMetadata](#create-user-metadata)
* [PubNubChannelMetadata](#create-channel-metadata)

### Create channels

This method returns a local `PubNubChannel` entity.

```python
pubnub.channel(String)
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: String | The ID of the [channel](https://www.pubnub.com/docs/general/channels/overview) to create a subscription of. |

#### Sample code

```python
pubnub.channel(f'{channel1}')
```

### Create channel groups

This method returns a local `PubNubChannelGroup` entity.

```python
pubnub.channel_group(String)
```

| Parameter | Description |
| --- | --- |
| `channel_group` *Type: String | The name of the [channel group](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to create a subscription of. |

#### Sample code

```python
pubnub.channel_group("channelGroupName")
```

### Create channel metadata

This method returns a local `PubNubChannelMetadata` entity.

```python
pubnub.channel_metadata(String)
```

| Parameter | Description |
| --- | --- |
| `channel_metadata` *Type: String | The String identifier of the [channel metadata](https://www.pubnub.com/docs/general/metadata/channel-metadata) object to create a subscription of. |

#### Sample code

```python
pubnub.channel_metadata("channelMetadata")
```

### Create user metadata

This method returns a local `PubNubUserMetadata` entity.

```python
pubnub.user_metadata(String)
```

| Parameter | Description |
| --- | --- |
| `user_metadata` *Type: String | The String identifier of the [user metadata](https://www.pubnub.com/docs/general/metadata/users-metadata) object to create a subscription of. |

#### Sample code

```python
pubnub.userMetadata("user_metadata")
```

## Event listeners

Messages and events are received in your app using a listener. This listener is a single point for all messages, signals, and events.

You can attach listeners to the instances of [Subscription](#create-a-subscription), [SubscriptionSet](#create-a-subscription-set), and, in the case of the connection status, the PubNub client.

:::note No built-in event throttling
The PubNub SDK delivers every incoming event to your listener as it arrives — there is no built-in throttling or rate-limiting on the subscriber side. If you need to control how often your application processes events, wrap your listener callback with a throttle or debounce utility from your language or framework ecosystem.
To reduce the number of messages delivered to your client in the first place, use [Subscribe Filters](https://www.pubnub.com/docs/general/channels/subscribe-filters) to filter messages server-side before they reach your listener.
:::

### Add listeners

You can implement multiple listeners or register an event-specific listener that receives only a selected type, like `message` or `file`.

#### Method(s)

```python
# Add event-specific listeners

# using closure for reusable listener
def on_message(listener):
    def message_callback(message):
        print(f"\033[94mMessage received on: {listener}: \n{message.message}\033[0m\n")
    return message_callback

# without closure
def on_message_action(message_action):
    print(f"\033[5mMessageAction received: \n{message_action.value}\033[0m\n")

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

def on_status(listener):
    def status_callback(status):
        print(f"\033[92mStatus received on: {listener}: \t{status.category.name}\033[0m")
    return status_callback

def on_signal(listener):
    def signal_callback(signal):
        print(f"\033[0;36mSignal received on: {listener}: \n{signal.publisher} says: \t{signal.message}\033[0m")
    return signal_callback

def on_channel_metadata(listener):
    def channel_metadata_callback(channel_meta):
        print(f"\033[0;36mChannel metadata received on: {listener}: \n{channel_meta.__dict__}\033[0m")
    return channel_metadata_callback

def on_user_metadata(listener):
    def user_metadata_callback(user_meta):
        print(f"\033[0;36mUser metadata received on: {listener}: \n{user_meta.__dict__}\033[0m")
    return user_metadata_callback

def on_file(listener):
    def file_callback(files):
        print(f"\033[0;36mFile received on: {listener}: \n{user_meta.__dict__}\033[0m")
    return file_callback

subscription.on_message = on_message('message_listener')
subscription.on_message_action = on_message_action

# add generic listener
class PrintListener(SubscribeCallback):
    def status(self, _, status):
        print(f'\033[92mPrintListener.status:\n{status.category.name}\033[0m')

    def message(self, _, message):
        print(f'\033[94mPrintListener.message:\n{message.message}\033[0m')

    def presence(self, _, presence):
        print(f'PrintListener.presence:\n{presence.uuid} {presence.event}s '
              f'{presence.subscription or presence.channel}\033[0m')

    def signal(self, _, signal):
        print(f'PrintListener.signal:\n{signal.message} from {signal.publisher}\033[0m')

    def channel(self, _, channel):
        print(f'\033[0;37mChannel Meta:\n{channel.__dict__}\033[0m')

    def uuid(self, _, uuid):
        print(f'User Meta:\n{uuid.__dict__}\033[0m')

    def membership(self, _, membership):
        print(f'Membership:\n{membership.__dict__}\033[0m')

    def message_action(self, _, message_action):
        print(f'PrintListener.message_action {message_action}\033[0m')

    def file(self, _, file_message):
        print(f' {file_message.__dict__}\033[0m')
```

#### Sample code

```python
subscription = pubnub.channel(f'{channel1}').subscription()

def on_message(listener):
    def message_callback(message):
        print(f"\033[94mMessage received on: {listener}: \n{message.message}\033[0m\n")
    return message_callback

def on_message_action(message_action):
    print(f"\033[5mMessageAction received: \n{message_action.value}\033[0m\n")

subscription.on_message = on_message('message_listener')
subscription.on_message_action = on_message_action

subscription.subscribe()

subscription_set = pubnub.subscription_set(channels=["channel", "channel2"],
                                          channel_groups=["cg_1"],
                                          with_presence=True)

subscription_set.subscribe()
```

### Add connection status listener

The PubNub client has a listener dedicated to handling connection status updates.

:::warning Client scope
This listener is only available on the PubNub object.
:::

#### Method(s)

```python
pubnub.add_listener()
```

#### Sample code

```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)
```

#### Returns

The subscription status. For information about available statuses, refer to [SDK statuses](https://www.pubnub.com/docs/general/setup/connection-management#sdk-statuses).

## Unsubscribe

Stop receiving real-time updates from a [Subscription](#create-a-subscription) or a [SubscriptionSet](#create-a-subscription-set).

### Method(s)

```python
subscription.unsubscribe()

subscription_set.unsubscribe()
```

### Sample code

```python
channel = pubnub.channel(f'{channel}')
t1_subscription = channel.subscription()
t1_subscription.subscribe()

subscription_set1 = pubnub.subscription_set(channels=['channel1', 'channel2'])
subscription_set.subscribe()

t1_subscription1.unsubscribe()
subscription_set.unsubscribe()
```

### Returns

None

## Unsubscribe all

Stop receiving real-time updates from all data streams and remove the entities associated with them.

:::warning Client scope
This method is only available on the PubNub object.
:::

### Method(s)

```python
pubnub.unsubscribe_all()
```

### Sample code

```python
channel = pubnub.channel(f'{channel}')
t1_subscription = channel.subscription()
t1_subscription.subscribe()

subscription_set1 = pubnub.subscription_set(channels=['channel1', 'channel2'])
subscription_set.subscribe()

t1_subscription1.unsubscribe()
subscription_set.unsubscribe()

pubnub.unsubscribe_all()
```

### Returns

None

## Subscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Subscribe](#subscribe) instead.
:::

#### Receive messages

Your app receives messages and events via event listeners. The event listener is a single point through which your app receives all the messages, signals, and events that are sent in any channel you are subscribed to.

For more information about adding a listener, refer to the [Event Listeners](https://www.pubnub.com/docs/sdks/python/api-reference/configuration#event-listeners) section.

#### Description

This function causes the client to create an open TCP socket to the PubNub Real-Time Network and begin listening for messages on a specified `channel`. To subscribe to a `channel` the client must send the appropriate `subscribe_key` at initialization.

By default a newly subscribed client will only receive messages published to the channel after the `subscribe()` call completes. If a client gets disconnected from a channel, it can automatically attempt to reconnect to that `channel` and retrieve any available messages that were missed during that period. This can be achieved by setting `setReconnectionPolicy` to `PNReconnectionPolicy.LINEAR`, when [initializing](https://www.pubnub.com/docs/sdks/asyncio/api-reference/configuration#initialization) the client.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s)

To `Subscribe to a channel` you can use the following method(s) in the Python SDK:

```python
pubnub.subscribe() \
    .channels(String|List|Tuple) \
    .channel_groups(String|List|Tuple) \
    .with_timetoken(Int) \
    .with_presence() \
    .execute()
```

| Parameter | Description |
| --- | --- |
| `channels`Type: String | List | Tuple | Subscribe to `channels`, Either `channel` or `channel_group` is required. |
| `channel_groups`Type: String | List | Tuple | Subscribe to `channel_groups`, Either `channel` or `channel_group` is required. |
| `timetoken`Type: Int | Pass a `timetoken`. |
| `with_presence`Type: Command | Also subscribe to related presence information. |

#### Sample code

Subscribe to a channel:

```python
pubnub.subscribe() \
    .channels('my_channel') \
    .execute()
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](https://www.pubnub.com/docs/sdks/python#add-event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Returns

:::note PNMessageResult
`PNMessageResult` is returned in the [Listeners](https://www.pubnub.com/docs/sdks/python#add-event-listeners)
:::

The `subscribe()` operation returns a `PNStatus` for messages which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| `category` | PNStatusCategory | See the [Python SDK listener categories](https://www.pubnub.com/docs/sdks/python/status-events). |
| `is_error` | Boolean | This is `True` if an error occurred in the execution of the operation. |
| `error_data` | PNErrorData | Error data of the exception (if `Error` is `True`). |
| `status_code` | int | Status code of the execution. |

The `subscribe()` operation returns a `PNMessageResult` for messages which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| `message` | Object | The `message` sent on a `channel` ID. |
| `subscription` | String | The channel group or wildcard `subscription` match (if exists). |
| `channel` | String | The `channel` ID for which the message belongs. |
| `timetoken` | Int | `Timetoken` for the message. |
| `user_metadata` | Dictionary | User `metadata`. |

The `subscribe()` operation returns a `PNPresenceEventResult` from presence which contains the following operations:

| Field | Type | Description |
| --- | --- | --- |
| `event` | String | Events like `join`, `leave`, `timeout`, `state-change`. |
| `uuid` | String | `uuid` for event. |
| `timestamp` | Int | `timestamp` for event. |
| `occupancy` | Int | Current `occupancy`. |
| `subscription` | String | The channel group or wildcard `subscription` match (if exists). |
| `channel` | String | The `channel` ID for which the message belongs. |
| `timetoken` | Int | `timetoken` of the message. |
| `user_metadata` | Dictionary | User `metadata`. |

The `subscribe()` operation returns a `PNSignalResult` for signals which contains the following operations:

| Field | Type | Description |
| --- | --- | --- |
| `timetoken` | Int | An int representation of the `timetoken` when Signal was sent. |
| `channel` | String | The `channel` ID on which Signal occurred. |
| `publisher` | String | ID of the sender. |
| `message` | Object | The payload. |

#### Other examples

##### Subscribe with logging

```python
import logging
import pubnub

from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub, SubscribeListener

pubnub.set_stream_logger('pubnub', logging.DEBUG)

pnconfig = PNConfiguration()

pnconfig.subscribe_key = 'demo'
pnconfig.publish_key = 'demo'

pubnub = PubNub(pnconfig)

pubnub.add_listener(SubscribeListener())
pubnub.subscribe().channels("my_channel").execute()
```

For more information, refer to [Logging](https://www.pubnub.com/docs/sdks/asyncio/logging).

##### Subscribing to multiple channels

Subscribe to multiple channels using [Multiplexing](https://www.pubnub.com/docs/general/channels/subscribe#channel-multiplexing). The example uses an array of channel names.

:::note Alternative subscription methods
You can also use [Wildcard Subscribe](https://www.pubnub.com/docs/general/channels/subscribe#wildcard-subscribe) and [Channel Groups](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to subscribe to multiple channels at a time. To use these features, the *Stream Controller* add-on must be enabled on your keyset in the [Admin Portal](https://admin.pubnub.com).
:::

```python
pubnub.subscribe() \
    .channels(["my_channel1", "my_channel2"]) \
    .execute()
```

##### Subscribing to a Presence channel

:::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).
:::

For any given channel there is an associated Presence channel. You can subscribe directly to the channel by appending `-pnpres` to the channel name. For example the channel named `my_channel` would have the presence channel named `my_channel-pnpres`.

```python
pubnub.subscribe()\
    .channels("my_channel")\
    .with_presence()\
    .execute()
```

##### Sample responses

###### Join event

```python
if envelope.event == 'join':
    envelope.uuid # 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    envelope.timestamp # 1345546797
    envelope.occupancy # 2
```

###### Leave event

```json
{
    "action" : "leave",
    "timestamp" : 1345549797,
    "uuid" : "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "occupancy" : 1
}
```

###### Timeout event

```python
if envelope.event == 'timeout':
    envelope.uuid # 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    envelope.timestamp # 1345546797
    envelope.occupancy # 0
```

###### State change event

```python
if envelope.event == 'state-change':
    envelope.uuid # 76c2c571-9a2b-d074-b4f8-e93e09f49bd
    envelope.timestamp # 1345546797
    envelope.user_metadata # {'is_typing': True}
```

##### Interval event

```json
{
    "action":"interval",
    "timestamp":1474396578,
    "occupancy":2
}
```

When a channel is in interval mode with `presence_deltas` `pnconfig` flag enabled, the interval message may also include the following fields which contain an array of changed UUIDs since the last interval message.

* joined
* left
* timedout

For example, this interval message indicates there were 2 new UUIDs that joined and 1 timed out UUID since the last interval:

```json
{
    "action" : "interval",
    "occupancy" : <# users in channel>,
    "timestamp" : <unix timestamp>,
    "joined" : ["uuid2", "uuid3"],
    "timedout" : ["uuid1"]
}
```

If the full interval message is greater than `30 KB` (since the max publish payload is `∼32 KiB`), none of the extra fields will be present. Instead there will be a `here_now_refresh` boolean field set to `True`. This indicates to the user that they should do a `hereNow` request to get the complete list of users present in the channel.

```json
{
    "action" : "interval",
    "occupancy" : <# users in channel>,
    "timestamp" : <unix timestamp>,
    "here_now_refresh" : True
}
```

##### Wildcard subscribe to channels

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/) (with Enable Wildcard Subscribe checked). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

Wildcard subscribes allow the client to subscribe to multiple channels using wildcard. For example, if you subscribe to `a.*` you will get all messages for `a.b`, `a.c`, `a.x`. The wildcarded `*` portion refers to any portion of the channel string name after the `dot (.)`.

```python
pubnub.subscribe() \
    .channels("foo.*") \
    .execute()
```

:::note Wildcard grants and revokes
Only one level (`a.*`) of wildcarding is supported. If you grant on `*` or `a.b.*`, the grant will treat `*` or `a.b.*` as a single channel named either `*` or `a.b.*`. You can also revoke permissions from multiple channels using wildcards but only if you previously granted permissions using the same wildcards. Wildcard revokes, similarly to grants, only work one level deep, like `a.*`.
:::

##### Subscribing with 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).
:::

:::note Required User ID
Always set the `user_id` to uniquely identify the user or device that connects to PubNub. This `user_id` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `user_id`, you won't be able to connect to PubNub.
:::

```python
from pubnub.enums import PNStatusCategory

from pubnub.pubnub import SubscribeListener, PubNub

class MySubscribeListener(SubscribeListener):
    def __init__(self):
        if status.category == PNStatusCategory.PNConnectedCategory:
            state = {
                'field_a': 'awesome',
                'field_b': 10
            }
            envelope = pubnub.set_state().channels('my_channel').\
                channel_groups('awesome_channel_groups').state(state).sync()

        else:
            pass

    def status(self, pubnub, status):
        pass

    def message(self, pubnub, message):
        pass

    def presence(self, pubnub, presence):
        pass

pubnub = PubNub(pnconfig)

my_listener = MySubscribeListener()
pubnub.add_listener(my_listener)

pubnub.subscribe().channels("my_channel").execute()
```

##### Subscribe to a channel group

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```python
pubnub.subscribe() \
    .channel_groups("awesome_channel_group") \
    .execute()
```

##### Subscribe to the Presence channel of a channel group

:::note Requires Stream Controller and Presence add-ons
This method requires both the *Stream Controller* and *Presence* add-ons are enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```python
pubnub.subscribe() \
    .channel_groups("awesome_channel_group") \
    .with_presence() \
    .execute()
```

#### Event listeners

You can be notified of connectivity status, message and presence notifications via the listeners.

Listeners should be added before calling the method.

##### Add listeners

```python
from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNOperationType, PNStatusCategory

class MySubscribeCallback(SubscribeCallback):
    def message(self, pubnub, message):
        print("Message channel: %s" % message.channel)
        print("Message subscription: %s" % message.subscription)
        print("Message timetoken: %s" % message.timetoken)
        print("Message payload: %s" % message.message)
        print("Message publisher: %s" % message.publisher)

    def presence(self, pubnub, presence):
        # Can be join, leave, state-change, timeout, or interval
        print("Presence event: %s" % presence.event)

        # The channel to which the message was published
        print("Presence channel: %s" % presence.channel)

        # Number of users subscribed to the channel
        print("Presence occupancy: %s" % presence.occupancy)

        # User state
        print("Presence state: %s" % presence.state)

        # Channel group or wildcard subscription match, if any
        print("Presence subscription: %s" % presence.subscription)

        # UUID to which this event is related
        print("Presence UUID: %s" % presence.uuid)

        # Publish timetoken
        print("Presence timestamp: %s" % presence.timestamp)

        # Current timetoken
        print("Presence timetoken: %s" % presence.timetoken)

        # List of users that have joined the channel (if event is 'interval')
        joined = presence.join

        # List of users that have left the channel (if event is 'interval')
        left = presence.leave

        # List of users that have timed-out off the channel (if event is 'interval')
        timed_out = presence.timeout

    def status(self, pubnub, status):

        # The status object returned is always related to subscribe but could contain
        # information about subscribe, heartbeat, or errors
        # use the operationType to switch on different options
        if status.operation == PNOperationType.PNSubscribeOperation \
                or status.operation == PNOperationType.PNUnsubscribeOperation:
            if status.category == PNStatusCategory.PNConnectedCategory:
                pass
                # This is expected for a subscribe, this means there is no error or issue whatsoever
            elif status.category == PNStatusCategory.PNReconnectedCategory:
                pass
                # This usually occurs if subscribe temporarily fails but reconnects. This means
                # there was an error but there is no longer any issue
            elif status.category == PNStatusCategory.PNDisconnectedCategory:
                pass
                # This is the expected category for an unsubscribe. This means there
                # was no error in unsubscribing from everything
            elif status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
                pass
                # This is usually an issue with the internet connection, this is an error, handle
                # appropriately retry will be called automatically
            elif status.category == PNStatusCategory.PNAccessDeniedCategory:
                pass
                # This means that Access Manager does not allow this client to subscribe to this
                # channel and channel group configuration. This is another explicit error
            else:
                pass
                # This is usually an issue with the internet connection, this is an error, handle appropriately
                # retry will be called automatically
        elif status.operation == PNOperationType.PNSubscribeOperation:
            # Heartbeat operations can in fact have errors, so it is important to check first for an error.
            # For more information on how to configure heartbeat notifications through the status
            # PNObjectEventListener callback, consult http://www.pubnub.com/docs/sdks/python/api-reference/configuration#configuration
            if status.is_error():
                pass
                # There was an error with the heartbeat operation, handle here
            else:
                pass
                # Heartbeat operation was successful
        else:
            pass
            # Encountered unknown status type

    def signal(self, pubnub, signal):
        print("Signal channel: %s" % signal.channel)
        print("Signal subscription: %s" % signal.subscription)
        print("Signal timetoken: %s" % signal.timetoken)
        print("Signal payload: %s" % signal.message)
        print("Signal publisher: %s" % signal.publisher)

    def message_action(self, pubnub, message_action):
        print("Message action type: %s" % message_action.type)
        print("Message action value: %s" % message_action.value)
        print("Message action uuid: %s" % message_action.uuid)
        print("Message action action_timetoken: %s" % message_action.action_timetoken)
        print("Message action message_timetoken: %s" % message_action.message_timetoken)

pubnub.add_listener(MySubscribeCallback())
```

##### Remove listeners

```python
my_listener = MySubscribeCallback()

pubnub.add_listener(my_listener)

# some time later
pubnub.remove_listener(my_listener)
```

##### Handling disconnects

```python
from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNStatusCategory

class HandleDisconnectsCallback(SubscribeCallback):
    def status(self, pubnub, status):
        if status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
            # internet got lost, do some magic and call reconnect when ready
            pubnub.reconnect()
        elif status.category == PNStatusCategory.PNTimeoutCategory:
            # do some magic and call reconnect when ready
            pubnub.reconnect()
        else:
            logger.debug(status)

    def presence(self, pubnub, presence):
        pass

    def message(self, pubnub, message):
        pass

    def signal(self, pubnub, signal):
        pass

disconnect_listener = HandleDisconnectsCallback()

pubnub.add_listener(disconnect_listener)
```

##### Listener status events

| Category | Description |
| --- | --- |
| `PNTimeoutCategory` | Failure to establish a connection to PubNub due to a timeout. |
| `PNBadRequestCategory` | The server responded with a bad response error because the request is malformed. |
| `PNNetworkIssuesCategory` | A subscribe event experienced an exception when running. The SDK isn't able to reach PubNub servers. This may be due to many reasons, such as: the machine or device isn't connected to the internet; the internet connection has been lost; your internet service provider is having trouble; or, perhaps the SDK is behind a proxy. |
| `PNReconnectedCategory` | The SDK was able to reconnect to PubNub. |
| `PNConnectedCategory` | SDK subscribed with a new mix of channels. This is fired every time the `channel` or `channel group` mix changes. |
| `PNUnexpectedDisconnectCategory` | Previously started subscribe loop did fail and at this moment client disconnected from real-time data channels. |
| `PNUnknownCategory` | Returned when the subscriber gets a non-200 HTTP response code from the server. |

`SubscribeListener` should not be used with high-performance sections of your app.

## Unsubscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe](#unsubscribe) instead.
:::

When subscribed to a single channel, this function causes the client to issue a `leave` from the `channel` and close any open socket to the PubNub Network. For multiplexed channels, the specified `channel`(s) will be removed and the socket remains open until there are no more channels remaining in the list.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s)

To `Unsubscribe from a channel` you can use the following method(s) in the Python SDK:

```python
pubnub.unsubscribe() \
    .channels(String|List|Tuple) \
    .channel_groups(String|List|Tuple) \
    .execute()
```

| Parameter | Description |
| --- | --- |
| `channels`Type: String | List | Tuple | Subscribe to `channels`, Either `channel` or `channel_group` is required. |
| `channel_groups`Type: String | List | Tuple | Subscribe to `channel_groups`, Either `channel` or `channel_group` is required |

#### Sample code

Unsubscribe from a channel:

```python
pubnub.unsubscribe() \
    .channels("my_channel") \
    .execute()
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](https://www.pubnub.com/docs/sdks/python#add-event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Response

The output below demonstrates the response to a successful call:

```python
if envelope.event == 'leave':
    envelope.uuid # 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    envelope.timestamp # 1345546797
    envelope.occupancy # 2
```

#### Other examples

##### Unsubscribing from multiple channels

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```python
pubnub.unsubscribe() \
    .channels(["my_channel1", "my_channel2"]) \
    .execute()
```

###### Example response

```json
{
    "action" : "leave"
}
```

##### Unsubscribe from a channel group

```python
pubnub.unsubscribe() \
    .channels_groups(["my_group1", "my_group2") \
    .execute()
```

**Example Response:** [](#unsubscribe-example-2-response)

```javascript
{
    "action": "leave"
}
```

## Unsubscribe all (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe All](#unsubscribe-all) instead.
:::

Unsubscribe from all channels and all channel groups.

#### Method(s)

```python
pubnub.unsubscribe_all()
```

#### Sample code

```python
pubnub.unsubscribe_all()
```

#### Returns

None

## Terms in this document

* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Channel pattern** - A way to group and analyze channel data to track performance metrics like message counts and user engagement over time with PubNub Insights.
* **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.