---
source_url: https://www.pubnub.com/docs/general/messages/receive
title: Receive Messages
updated_at: 2026-05-25T11:26:21.504Z
---

> 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


# Receive Messages

Messages sent through PubNub are PubNub events with a message payload. They are only [structured](https://www.pubnub.com/docs/general/messages/publish) differently.

Channels are unique identifiers that carry real-time messages between publishers and subscribers. See [channels](https://www.pubnub.com/docs/general/channels/overview) for details.

Receiving messages (and other events) is a three-step process:

1. [Create](https://www.pubnub.com/docs/general/entities) an entity-based subscription or a subscription set.
2. [Implement](#add-an-event-handler) the appropriate event listener.
3. [Subscribe](https://www.pubnub.com/docs/general/channels/subscribe) to the subscription to receive real-time updates.

:::warning Entity-enabled SDKs
Not all PubNub SDKs support entities yet. For SDKs that still use legacy event listeners and the Subscribe API, see their SDK API docs.
Refer to the [API documentation](https://www.pubnub.com/docs/sdks) of each SDK for more information.
:::

## Add an event handler

Messages and events are received using a listener (a callback function). In the listener, add logic for messages, signals, files, presence, and other events.

Add listeners to subscriptions and subscription sets to handle one or many subscriptions.

There are four entities:

* [Channel](https://www.pubnub.com/docs/general/entities#channel-entity)
* [ChannelGroup](https://www.pubnub.com/docs/general/entities#channelgroup-entity)
* [UserMetadata](https://www.pubnub.com/docs/general/entities#usermetadata-entity)
* [ChannelMetadata](https://www.pubnub.com/docs/general/entities#channelmetadata-entity)

Each message or event type has its own handler where you implement app logic for the received data.

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

When you no longer need to handle events, remove the listener using the SDK method. See [JavaScript SDK](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration#event-listeners) as an example.

You can receive events using the following approaches:

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

The following handlers are available:

:::note User ID / UUID
User ID is also referred to as **UUID/uuid** in some APIs and server responses but **holds the value** of the **userId** parameter you [set during initialization](https://www.pubnub.com/docs/general/setup/users-and-devices#set-the-user-id).
:::

###### JavaScript

```javascript
// create a subscription from a channel entity
const channel = pubnub.channel('channel_1');
const subscription = channel.subscription();

// Event-specific listeners
subscription.onMessage =  (messageEvent) => { console.log("Message event: ", messageEvent); };
subscription.onPresence =  (presenceEvent) => { console.log("Presence event: ", presenceEvent); };
subscription.onMessage = (messageEvent) => { console.log("Message event: ", messageEvent); };
subscription.onPresence = (presenceEvent) => { console.log("Presence event: ", presenceEvent); };
subscription.onSignal = (signalEvent) => { console.log("Signal event: ", signalEvent); };
subscription.onObjects = (objectsEvent) => { console.log("Objects event: ", objectsEvent); };
subscription.onMessageAction = (messageActionEvent) => { console.log("Message Action event: ", messageActionEvent); };
subscription.onFile = (fileEvent) => { console.log("File event: ", fileEvent); };

// Generic listeners
subscription.addListener({
  // Messages
  message: function (m) {
    const channelName = m.channel; // Channel on which the message was published
    const channelGroup = m.subscription; // Channel group or wildcard subscription match (if exists)
    const pubTT = m.timetoken; // Publish timetoken
    const msg = m.message; // Message payload
    const publisher = m.publisher; // Message publisher
  },
  // Presence
  presence: function (p) {
    const action = p.action; // Can be join, leave, timeout, state-change, or interval
    const channelName = p.channel; // Channel to which the message belongs
    const occupancy = p.occupancy; // Number of users subscribed to the channel
    const state = p.state; // User state
    const channelGroup = p.subscription; //  Channel group or wildcard subscription match, if any
    const publishTime = p.timestamp; // Publish timetoken
    const timetoken = p.timetoken; // Current timetoken
    const uuid = p.uuid; // UUIDs of users who are subscribed to the channel
  },
  // Signals
  signal: function (s) {
    const channelName = s.channel; // Channel to which the signal belongs
    const channelGroup = s.subscription; // Channel group or wildcard subscription match, if any
    const pubTT = s.timetoken; // Publish timetoken
    const msg = s.message; // Payload
    const publisher = s.publisher; // Message publisher
  },
  // App Context
  objects: (objectEvent) => {
    const channel = objectEvent.channel; // Channel to which the event belongs
    const channelGroup = objectEvent.subscription; // Channel group
    const timetoken = objectEvent.timetoken; // Event timetoken
    const publisher = objectEvent.publisher; // UUID that made the call
    const event = objectEvent.event; // Name of the event that occurred
    const type = objectEvent.type; // Type of the event that occurred
    const data = objectEvent.data; // Data from the event that occurred
  },
  // Message Actions
  messageAction: function (ma) {
    const channelName = ma.channel; // Channel to which the message belongs
    const publisher = ma.publisher; // Message publisher
    const event = ma.event; // Message action added or removed
    const type = ma.data.type; // Message action type
    const value = ma.data.value; // Message action value
    const messageTimetoken = ma.data.messageTimetoken; // Timetoken of the original message
    const actionTimetoken = ma.data.actionTimetoken; // Timetoken of the message action
  },
  // File Sharing
  file: function (event) {
    const channelName = event.channel; // Channel to which the file belongs
    const channelGroup = event.subscription; // Channel group or wildcard subscription match (if exists)
    const publisher = event.publisher; // File publisher
    const timetoken = event.timetoken; // Event timetoken

    const message = event.message; // Optional message attached to the file
    const fileId = event.file.id; // File unique id
    const fileName = event.file.name;// File name
    const fileUrl = event.file.url; // File direct URL
  }
});
```

###### Swift

```swift
// Add event-specific listeners
// Add a listener to receive Message changes
subscription.onMessage = { message in
  print("Message Received: \(message) Publisher: \(message.publisher ?? "defaultUUID")")
}

// Add a listener to receive Presence changes
subscription.onPresence = { presenceChange in
  for action in presenceChange.actions {
    switch action {
    case let .join(uuids):
      print("The following list of occupants joined at \(presenceChange.timetoken): \(uuids)")
    case let .leave(uuids):
      print("The following list of occupants left at \(presenceChange.timetoken): \(uuids)")
    case let .timeout(uuids):
      print("The following list of occupants timed-out at \(presenceChange.timetoken): \(uuids)")
    case let .stateChange(uuid, state):
      print("\(uuid) changed their presence state to \(state) at \(presenceChange.timetoken)")
    }
  }
}

// Add a listener to receive Message Action events
subscription.onMessageAction = { messageActionEvent in
  switch messageActionEvent {
  case .added(let messageAction):
    print("The \(messageAction.channel) channel received a message at \(messageAction.messageTimetoken)")
  case .removed(let messageAction):
    print("A message action with the timetoken of \(messageAction.actionTimetoken) has been removed")
  }
}

// Add a listener to receive App Context events
subscription.onAppContext = { appContextEvent in
  switch appContextEvent {
  case let .userMetadataSet(uuidMetadataChange):
    print("Changes were made to \(uuidMetadataChange.metadataId) at \(uuidMetadataChange.updated)")
  case let .userMetadataRemoved(metadataId):
    print("Metadata for the uuid \(metadataId) has been removed")
  case let .channelMetadataSet(channelMetadata):
    print("Changes were made to \(channelMetadata.metadataId) at \(channelMetadata.updated)")
  case let .channelMetadataRemoved(metadataId: metadataId):
    print("Metadata for the channel \(metadataId) has been removed")
  case let .membershipMetadataSet(membership):
    print("A membership was set between \(membership.uuidMetadataId) and \(membership.channelMetadataId)")
  case let .membershipMetadataRemoved(membership):
    print("A membership was removed between \(membership.uuidMetadataId) and \(membership.channelMetadataId)")
  }
}

// Add a listener to receive File events
subscription.onFileEvent = { fileEvent in
  if case let .uploaded(fileInfo) = fileEvent {
    print("A file \(fileInfo) was uploaded")
  }
}

// Add a batched subscription event that possibly contains multiple events
subscription.onEvents = { events in
  print("Did receive events: \(events)")
}

// Add multiple listeners
subscription.onEvent = { event in
  switch event {
  case let .messageReceived(message):
    print("Message Received: \(message) Publisher: \(message.publisher ?? "defaultUUID")")
  case let .signalReceived(signal):
    print("Signal Received: \(signal)")
  case let .presenceChanged(presence):
    print("Presence Received: \(presence)")
  case let .appContextChanged(appContextEvent):
    print("App Context changed: \(appContextEvent)")
  case let .messageActionChanged(messageActionEvent):
    print("Message Action event: \(messageActionEvent)")
  case let .fileChanged(fileEvent):
    print("File event: \(fileEvent)")
  default:
    break
  }
}
```

###### Objective-C

```objectivec
// Listener's class should conform to `PNEventsListener` protocol
// in order to have access to available callbacks.

// Adding listener.
[pubnub addListener:self];

// Callbacks listed below.

- (void)client:(PubNub *)pubnub didReceiveMessage:(PNMessageResult *)message {
    NSString *channel = message.data.channel; // Channel on which the message has been published
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = message.data.timetoken; // Publish timetoken
    id msg = message.data.message; // Message payload
    NSString *publisher = message.data.publisher; // Message publisher
}

- (void)client:(PubNub *)pubnub didReceiveSignal:(PNSignalResult *)signal {
    NSString *channel = message.data.channel; // Channel on which the signal has been published
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = message.data.timetoken; // Signal timetoken
    id msg = message.data.message; // Signal payload
    NSString *publisher = message.data.publisher; // Signal publisher
}

- (void)client:(PubNub *)pubnub didReceiveMessageAction:(PNMessageActionResult *)action {
    NSString *channel = action.data.channel; // Channel on which the message has been published
    NSString *subscription = action.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *event = action.data.event; // Can be: added or removed
    NSString *type = action.data.action.type; // Message action type
    NSString *value = action.data.action.value; // Message action value
    NSNumber *messageTimetoken = action.data.action.messageTimetoken; // Timetoken of the original message
    NSNumber *actionTimetoken = action.data.action.actionTimetoken; // Timetoken of the message action
    NSString *uuid = action.data.action.uuid; // UUID of user which added / removed message action
}

- (void)client:(PubNub *)pubnub didReceivePresenceEvent:(PNPresenceEventResult *)event {
    NSString *channel = message.data.channel; // Channel on which presence changes
    NSString *subscription = message.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *presenceEvent = event.data.presenceEvent; // Can be: join, leave, state-change, timeout or interval
    NSNumber *occupancy = event.data.presence.occupancy; // Number of users subscribed to the channel (not available for state-change event)
    NSNumber *timetoken = event.data.presence.timetoken; // Presence change timetoken
    NSString *uuid = event.data.presence.uuid; // UUID of user for which presence change happened

    // Only for 'state-change' event
    NSDictionary *state = event.data.presence.state; // User state (only for state-change event)

    // Only for 'interval' event
    NSArray<NSString *> *join = event.data.presence.join; // UUID of users which recently joined channel
    NSArray<NSString *> *leave = event.data.presence.leave; // UUID of users which recently leaved channel
    NSArray<NSString *> *timeout = event.data.presence.timeout; // UUID of users which recently timed out on channel
}

- (void)client:(PubNub *)pubnub didReceiveObjectEvent:(PNObjectEventResult *)event {
    NSString *channel = event.data.channel; // Channel to which the event belongs
    NSString *subscription = event.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSString *event = event.data.event; // Can be: set or delete
    NSString *type = event.data.type; // Entity type: channel, uuid or membership
    NSNumber *timestamp = event.data.timestamp; // Event timestamp

    PNChannelMetadata *channelMetadata = event.data.channelMetadata; // Updated channel metadata (only for channel entity type)
    PNUUIDMetadata *uuidMetadata = event.data.uuidMetadata; // Updated channel metadata (only for uuid entity type)
    PNMembership *membership = event.data.membership; // Updated channel metadata (only for membership entity type)
}

- (void)client:(PubNub *)pubnub didReceiveFileEvent:(PNFileEventResult *)event {
    NSString *channel = event.data.channel; // Channel to which file has been uploaded
    NSString *subscription = event.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    id message = event.data.message; // Message added for uploaded file
    NSString *publisher = event.data.publisher; // UUID of file uploader
    NSURL *fileDownloadURL = event.data.file.downloadURL; // URL which can be used to download file
    NSString *fileIdentifier = event.data.file.identifier; // Unique file identifier
    NSString *fileName = event.data.file.name; // Name with which file has been stored remotely
}

- (void)client:(PubNub *)pubnub didReceiveStatus:(PNStatus *)status {
    PNStatusCategory category = status.category; // One of PNStatusCategory fields to identify status of operation processing
    BOOL isError = status.isError; // Whether any kind of error happened.
    NSInteger statusCode = status.statusCode; // Related request processing status code
    BOOL isTLSEnabled = status.isTLSEnabled; // Whether secured connection enabled
    NSString *uuid = status.uuid; // UUID which configured for passed client
    NSString *authKey = status.authKey; // Auth token configured for passed client
    NSString *origin = status.origin; // Origin against which request has been sent
    NSURLRequest *clientRequest = status.clientRequest; // Request which has been used to send last request (may be nil)
    BOOL willAutomaticallyRetry = status.willAutomaticallyRetry; // Whether client will try to perform automatic retry

    // Following is available when operation == PNSubscribeOperation,
    // because status is PNSubscribeStatus instance in this case
    PNSubscribeStatus *subscribeStatus = (PNSubscribeStatus *)status;
    NSNumber *currentTimetoken = subscribeStatus.currentTimetoken; // Timetoken which has been used for current subscribe request
    NSNumber *lastTimeToken = subscribeStatus.lastTimeToken; // Timetoken which has been used for previous subscribe request
    NSArray<NSString *> *subscribedChannels = subscribeStatus.subscribedChannels; // List of channels on which client currently subscribed
    NSArray<NSString *> *subscribedChannelGroups = subscribeStatus.subscribedChannelGroups; // List of channel groups on which client currently subscribed
    NSString *channel = subscribeStatus.data.channel; // Name of channel to which status has been received
    NSString *subscription = subscribeStatus.data.subscription; // Wild-card channel or channel on which PubNub client actually subscribed
    NSNumber *timetoken = subscribeStatus.data.timetoken; // Timetoken at which event arrived
    NSDictionary *userMetadata = subscribeStatus.data.userMetadata; // Metadata / envelope which has been passed along with event

    // Following is available when isError == YES,
    // because status is PNErrorStatus instance in this case
    PNErrorStatus *errorStatus = (PNErrorStatus *)status;
    id associatedObject = errorStatus.associatedObject; // Data which may contain related information (not decrypted message for example)
    NSArray<NSString *> *erroredChannels = errorStatus.errorData.channels; // List of channels for which error reported (mostly because of Access Manager)
    NSArray<NSString *> *erroredChannelGroups = errorStatus.errorData.channelGroups; // List of channel groups for which error reported (mostly because of Access Manager)
    NSString *errorInformation = errorStatus.errorData.information; // Stringified information about error
    id errorData = errorStatus.errorData.data; // Additional error information from PubNub service
}
```

###### Java

```java
pubnub.addListener(new StatusListener() {
    // PubNub status
    @Override
    public void status(PubNub pubnub, PNStatus status) {
        switch (status.getCategory()) {
            /* case statements for various categories */
        }
    }
});

pubnub.addListener(new EventListener() {
    // Messages
    @Override
    public void message(PubNub pubnub, PNMessageResult message) {
        String messagePublisher = message.getPublisher();
        System.out.println("Message publisher: " + messagePublisher);
        System.out.println("Message Payload: " + message.getMessage());
        System.out.println("Message Subscription: " + message.getSubscription());
        System.out.println("Message Channel: " + message.getChannel());
        System.out.println("Message timetoken: " + message.getTimetoken());
    }

    // Presence
    @Override
    public void presence(@NotNull PubNub pubnub, @NotNull PNPresenceEventResult presence) {
        System.out.println("Presence Event: " + presence.getEvent());
        // Can be join, leave, state-change or timeout

        System.out.println("Presence Channel: " + presence.getChannel());
        // The channel to which the message was published

        System.out.println("Presence Occupancy: " + presence.getOccupancy());
        // Number of users subscribed to the channel

        System.out.println("Presence State: " + presence.getState());
        // User state

        System.out.println("Presence UUID: " + presence.getUuid());
        // User ID to which this event is related

        presence.getJoin();
        // List of users that have joined the channel (if event is 'interval')

        presence.getLeave();
        // List of users that have left the channel (if event is 'interval')

        presence.getTimeout();
        // List of users that have timed-out off the channel (if event is 'interval')

        presence.getHereNowRefresh();
        // Indicates to the client that it should call 'hereNow()' to get the
        // complete list of users present in the channel.
    }

    // Signals
    @Override
    public void signal(PubNub pubnub, PNSignalResult pnSignalResult) {
        System.out.println("Signal publisher: " + signal.getPublisher());
        System.out.println("Signal payload: " + signal.getMessage());
        System.out.println("Signal subscription: " + signal.getSubscription());
        System.out.println("Signal channel: " + signal.getChannel());
        System.out.println("Signal timetoken: " + signal.getTimetoken());
    }

    // Message actions
    @Override
    public void messageAction(PubNub pubnub, PNMessageActionResult pnActionResult) {
        PNMessageAction pnMessageAction = pnActionResult.getAction();
        System.out.println("Message action type: " + pnMessageAction.getType());
        System.out.println("Message action value: " + pnMessageAction.getValue());
        System.out.println("Message action uuid: " + pnMessageAction.getUuid());
        System.out.println("Message action actionTimetoken: " + pnMessageAction.getActionTimetoken());
        System.out.println("Message action messageTimetoken: " + pnMessageAction.getMessageTimetoken());]
        System.out.println("Message action subscription: " + pnActionResult.getSubscription());
        System.out.println("Message action channel: " + pnActionResult.getChannel());
        System.out.println("Message action timetoken: " + pnActionResult.getTimetoken());
    }

    // File Sharing
    @Override
    public void file(PubNub pubnub, PNFileEventResult pnFileEventResult) {
        System.out.println("File channel: " + pnFileEventResult.getChannel());
        System.out.println("File publisher: " + pnFileEventResult.getPublisher());
        System.out.println("File message: " + pnFileEventResult.getMessage());
        System.out.println("File timetoken: " + pnFileEventResult.getTimetoken());
        System.out.println("File file.id: " + pnFileEventResult.getFile().getId());
        System.out.println("File file.name: " + pnFileEventResult.getFile().getName());
        System.out.println("File file.url: " + pnFileEventResult.getFile().getUrl());
    }
});
```

###### C#

```csharp
// Add event-specific listeners
// Add a listener to receive Message changes
Subscription subscription1 = pubnub.Channel("channelName").Subscription()

subscription1.OnMessage = (Pubnub pn, PNMessageResult<object> messageEvent) => {
 Console.WriteLine($"Message received {messageEvent.Message}");
};

subscription1.Subscribe<object>()

// Add multiple listeners
SubscribeCallbackExt eventListener = new SubscribeCallbackExt(
 delegate (Pubnub pn, PNMessageResult<object> messageEvent) {
  Console.WriteLine($"received message {messageEvent.Message}");
 },
 delegate (Pubnub pn, PNPresenceEventResult e) {
  Console.WriteLine("Presence event");
 }
 delegate (Pubnub pn, PNSignalResult<object> e) {
  Console.WriteLine("Signal event");
 }
 delegate (Pubnub pn, PNMessageActionEventResult e) {
  Console.WriteLine("Message Action event");
 }
 delegate (Pubnub pn, PNObjectEventResult e) {
  Console.WriteLine("Object event");
 }
 delegate (Pubnub pn, PNFileEventResult e) {
  Console.WriteLine("File event");
 }
);

Channel firstChannel = pubnub.Channel("first");
var subscription = firstChannel.Subscription(SubscriptionOptions.ReceivePresenceEvents);
subscription.AddListener(eventListener);
subscription.Subscribe<object>();
```

###### Go

```go
import (
    pubnub "github.com/pubnub/go"
)

listener := pubnub.NewListener()

go func() {
    for {
        select {
            case signal := <-listener.Signal:
            // Channel
            fmt.Println(signal.Channel)
            // Subscription
            fmt.Println(signal.Subscription)
            // Payload
            fmt.Println(signal.Message)
            // Publisher ID
            fmt.Println(signal.Publisher)
            // Timetoken
            fmt.Println(signal.Timetoken)
        case status := <-listener.Status:
            switch status.Category {
                case pubnub.PNDisconnectedCategory:
                // This is the expected category for an unsubscribe. This means there
                // was no error in unsubscribing from everything.
            case pubnub.PNConnectedCategory:
                // This is expected for a subscribe. This means
                // there is no error or issue whatsoever.
            case pubnub.PNReconnectedCategory:
                // This usually occurs if subscribe temporarily fails but reconnects.
                // This means there was an error but there is no longer any issue.
            case pubnub.PNAccessDeniedCategory:
                // This means that Access Manager doesn't allow this client to subscribe to this
                // channel and channel group configuration. This is another explicit error.
            }
        case message := <-listener.Message:
            // Channel
            fmt.Println(message.Channel)
            // Subscription
            fmt.Println(message.Subscription)
            // Payload
            fmt.Println(message.Message)
            // Publisher ID
            fmt.Println(message.Publisher)
            // Timetoken
            fmt.Println(message.Timetoken)
        case presence := <-listener.Presence:
            fmt.Println(presence.Event)
            // Channel
            fmt.Println(presence.Channel)
            // Subscription
            fmt.Println(presence.Subscription)
           // Timetoken
            fmt.Println(presence.Timetoken)
           // Occupancy
            fmt.Println(presence.Occupancy)
        case uuidEvent := <-listener.UUIDEvent:
            fmt.Println(fmt.Sprintf("uuidEvent.Channel: %s", uuidEvent.Channel))
            fmt.Println(fmt.Sprintf("uuidEvent.SubscribedChannel: %s", uuidEvent.SubscribedChannel))
            fmt.Println(fmt.Sprintf("uuidEvent.Event: %s", uuidEvent.Event))
            fmt.Println(fmt.Sprintf("uuidEvent.UUID: %s", uuidEvent.UUID))
            fmt.Println(fmt.Sprintf("uuidEvent.Description: %s", uuidEvent.Description))
            fmt.Println(fmt.Sprintf("uuidEvent.Timestamp: %s", uuidEvent.Timestamp))
            fmt.Println(fmt.Sprintf("uuidEvent.Name: %s", uuidEvent.Name))
            fmt.Println(fmt.Sprintf("uuidEvent.ExternalID: %s", uuidEvent.ExternalID))
            fmt.Println(fmt.Sprintf("uuidEvent.ProfileURL: %s", uuidEvent.ProfileURL))
            fmt.Println(fmt.Sprintf("uuidEvent.Email: %s", uuidEvent.Email))
            fmt.Println(fmt.Sprintf("uuidEvent.Updated: %s", uuidEvent.Updated))
            fmt.Println(fmt.Sprintf("uuidEvent.ETag: %s", uuidEvent.ETag))
            fmt.Println(fmt.Sprintf("uuidEvent.Custom: %v", uuidEvent.Custom))
        case channelEvent := <-listener.ChannelEvent:
            fmt.Println(fmt.Sprintf("channelEvent.Channel: %s", channelEvent.Channel))
            fmt.Println(fmt.Sprintf("channelEvent.SubscribedChannel: %s", channelEvent.SubscribedChannel))
            fmt.Println(fmt.Sprintf("channelEvent.Event: %s", channelEvent.Event))
            fmt.Println(fmt.Sprintf("channelEvent.Channel: %s", channelEvent.Channel))
            fmt.Println(fmt.Sprintf("channelEvent.Description: %s", channelEvent.Description))
            fmt.Println(fmt.Sprintf("channelEvent.Timestamp: %s", channelEvent.Timestamp))
            fmt.Println(fmt.Sprintf("channelEvent.Updated: %s", channelEvent.Updated))
            fmt.Println(fmt.Sprintf("channelEvent.ETag: %s", channelEvent.ETag))
            fmt.Println(fmt.Sprintf("channelEvent.Custom: %v", channelEvent.Custom))
        case membershipEvent := <-listener.MembershipEvent:
            fmt.Println(fmt.Sprintf("membershipEvent.Channel: %s", membershipEvent.Channel))
            fmt.Println(fmt.Sprintf("membershipEvent.SubscribedChannel: %s", membershipEvent.SubscribedChannel))
            fmt.Println(fmt.Sprintf("membershipEvent.Event: %s", membershipEvent.Event))
            fmt.Println(fmt.Sprintf("membershipEvent.Channel: %s", membershipEvent.Channel))
            fmt.Println(fmt.Sprintf("membershipEvent.UUID: %s", membershipEvent.UUID))
            fmt.Println(fmt.Sprintf("membershipEvent.Description: %s", membershipEvent.Description))
            fmt.Println(fmt.Sprintf("membershipEvent.Timestamp: %s", membershipEvent.Timestamp))
            fmt.Println(fmt.Sprintf("membershipEvent.Custom: %v", membershipEvent.Custom))
        case messageActionsEvent := <-listener.MessageActionsEvent:
            fmt.Println(fmt.Sprintf("messageActionsEvent.Channel: %s", messageActionsEvent.Channel))
            fmt.Println(fmt.Sprintf("messageActionsEvent.SubscribedChannel: %s", messageActionsEvent.SubscribedChannel))
            fmt.Println(fmt.Sprintf("messageActionsEvent.Event: %s", messageActionsEvent.Event))
            fmt.Println(fmt.Sprintf("messageActionsEvent.Data.ActionType: %s", messageActionsEvent.Data.ActionType))
            fmt.Println(fmt.Sprintf("messageActionsEvent.Data.ActionValue: %s", messageActionsEvent.Data.ActionValue))
            fmt.Println(fmt.Sprintf("messageActionsEvent.Data.ActionTimetoken: %s", messageActionsEvent.Data.ActionTimetoken))
            fmt.Println(fmt.Sprintf("messageActionsEvent.Data.MessageTimetoken: %s", messageActionsEvent.Data.MessageTimetoken))
        case file := <-listener.File:
            fmt.Println(fmt.Sprintf("file.File.PNMessage.Text: %s", file.File.PNMessage.Text))
            fmt.Println(fmt.Sprintf("file.File.PNFile.Name: %s", file.File.PNFile.Name))
            fmt.Println(fmt.Sprintf("file.File.PNFile.ID: %s", file.File.PNFile.ID))
            fmt.Println(fmt.Sprintf("file.File.PNFile.URL: %s", file.File.PNFile.URL))
            fmt.Println(fmt.Sprintf("file.Channel: %s", file.Channel))
            fmt.Println(fmt.Sprintf("file.Timetoken: %d", file.Timetoken))
            fmt.Println(fmt.Sprintf("file.SubscribedChannel: %s", file.SubscribedChannel))
            fmt.Println(fmt.Sprintf("file.Publisher: %s", file.Publisher))
        }
    }
}
```

###### Python

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

subscription.add_listener(PrintListener())
```

###### Dart

```dart
subscription.messages.listen((envelope) {
    switch (envelope.messageType) {
      case MessageType.normal:
          print('${envelope.publishedBy} sent a message: ${envelope.content}');
          print('${envelope.channel}'); //to display the channel that message was sent on
          print('${envelope.publishedAt}'); // to display timetoken of the message received
          print('${envelope.content}'); // to display content of the message
          print('${envelope.uuid}'); // to display the User ID of the sender
          break;
      case MessageType.signal:
          print('${envelope.publishedBy} sent a signal message: ${envelope.content}');
          print('${envelope.channel}'); //to display the channel that message was sent on
          print('${envelope.publishedAt}'); // to display timetoken of the message received
          print('${envelope.content}'); // to display content of the message
          print('${envelope.uuid}'); // to display the User ID of the sender
        break;
      case MessageType.objects:
          print('object event received from ${envelope.publishedBy} with data ${envelope.payload['data']}');
          print('${envelope.channel}'); //to display the channel that message was sent on
          print('${envelope.publishedAt}'); // to display timetoken of the message received
          print('${envelope.content}'); // to display content of the message
          print('${envelope.uuid}'); // to display the User ID of the sender
        break;
      case MessageType.messageAction:
          print('message action event ${envelope.payload['event']} received with data ${envelope.payload['data']}');
          print('${envelope.channel}'); //to display the channel that message was sent on
          print('${envelope.publishedAt}'); // to display timetoken of the message received
          print('${envelope.content}'); // to display content of the message
          print('${envelope.uuid}'); // to display the User ID of the sender
        break;
      case MessageType.file:
          var fileInfo = envelope.payload['file'];
          var id = fileInfo['id']; // unique file id
          var name = fileInfo['name']; // file name
          print('${envelope.publishedBy} sends file $name with message  ${envelope.payload['message']}');
          print('${envelope.channel}'); //to display the channel that message was sent on
          print('${envelope.publishedAt}'); // to display timetoken of the message received
          print('${envelope.content}'); // to display content of the message
          print('${envelope.uuid}'); // to display the User ID of the sender
        break;
      default:
        print('${envelope.publishedBy} sent a message: ${envelope.content}');
    }
  });

  subscription.presence.listen((event) {
      print('''Presence Event with action: ${event.action},
      received from uuid: ${event.uuid}
      with time token: ${event.timetoken},
      Total Occupancy now is: ${event.occupancy}
      ''');
  });

var envelope =
    await subscription.messages.firstWhere((envelope) => envelope.channel == 'my_channel');
```

###### Kotlin

```kotlin
subscription.onMessage = { message ->
    /* Handle message */
}

subscription.onSignal = { signal ->
    /* Handle signal */
}

subscription.onMessageAction = { messageAction ->
    /* Handle message action */
}

subscription.onFile = { file ->
    /* Handle file event */
}

subscription.onObjects = { obj ->
    /* Handle metadata updates */
}

subscription.onPresence = { presence ->
    /* Handle presence updates */
}
```

The following is an overview of each of the event listeners. For a description of the payload fields for each event type, see [Event Types](https://www.pubnub.com/docs/general/events). Details about the data passed to the handlers' parameters will be explained in the API sections of the associated handlers.

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

| Handler | Description |
| --- | --- |
| Status | Receives events when the client connects (subscribes) or reconnects to channels. For other error events the Status handler can receive, see [Connection Management](https://www.pubnub.com/docs/general/channels/subscribe#status-events) and the tip that follows this table. In entity-enabled SDKs, add this listener to the `pubnub` object, not to an individual subscription. |
| Message | Receives all messages published to channels the client subscribes to. The event payload contains the published message data, publish timetoken, the user ID of the publisher, and more. See [Publish Messages](https://www.pubnub.com/docs/general/messages/publish). |
| Signal | Receives all signals sent to any subscribed channels. The event payload contains the signal data, signal timetoken, the user ID of the publisher, and more. See [Send Signals](https://www.pubnub.com/docs/general/messages/publish#send-signals). |
| Presence | Receives presence events on subscribed channels. Event types include `join`, `leave`, `timeout`, and `state-change`. The payload includes a timetoken for the action, the user ID, and optional state data. See [Detect Presence](https://www.pubnub.com/docs/general/presence/overview). |
| MessageAction | Receives events when messages are annotated by an action on any subscribed channels. The payload includes the user ID that acted, action type (such as an emoji reaction), timetoken of the annotated message, timetoken of the action, action value, and more. See [Message Actions](https://www.pubnub.com/docs/general/messages/actions). |
| Objects | Receives objects events when channel, membership, or user metadata is created, updated, or removed. See [App Context](https://www.pubnub.com/docs/general/metadata/basics). |

:::tip Status event handling
PubNub automatically tries to reconnect after transient network issues. For more about status events and troubleshooting, see [SDK troubleshooting and status event references](https://www.pubnub.com/docs/general/resources/troubleshooting#sdk-troubleshooting-and-status-event-references).
:::

## Terms in this document

* **Entity** - A subscribable object within a PubNub SDK that allows you to perform context-specific operations.
* **Listener** - A function or objectthat reacts to events or messages, like new chat messages or connection updates, letting your app respond in real-time.
