---
source_url: https://www.pubnub.com/docs/sdks/cocoa-objective-c/api-reference/message-actions
title: Message Actions API for Cocoa Objective-C SDK
updated_at: 2026-05-20T11:06:24.474Z
---

> 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


# Message Actions API for Cocoa Objective-C SDK

Use message actions to add or remove metadata on published messages. Common uses include receipts and reactions. Clients subscribe to a channel to receive message action events. Clients can also fetch past message actions from Message Persistence, either on demand or when fetching original messages.

:::tip Reactions
"Message Reactions" is a specific application of the Message Actions API for emoji or social reactions.
:::

:::note Message Actions vs. Message Reactions
**Message Actions** is the flexible, low-level API for adding any metadata to messages (read receipts, delivery confirmations, custom data), while **Message Reactions** specifically refers to using Message Actions for emoji/social reactions.
In PubNub [Core](https://www.pubnub.com/docs/sdks) and [Chat](https://www.pubnub.com/docs/chat/overview) SDKs, the same underlying Message Actions API is referred to as **Message Reactions** when used for emoji reactions - it's the same functionality, just different terminology depending on the use case.
:::

## Add message action

:::warning Requires Message Persistence
Enable Message Persistence for your key in the [Admin Portal](https://admin.pubnub.com/) as described in the [support article](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-).
:::

Add an action to a published message. The response includes the added action.

### Method(s)

Use this Cocoa method:

```objectivec
- (void)addMessageActionWithRequest:(PNAddMessageActionRequest *)request
                         completion:(nullable PNAddMessageActionCompletionBlock)block;
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| request | PNAddMessageActionRequest | Yes |  | Request containing the message action details. |
| block | PNAddMessageActionCompletionBlock | Optional |  | Completion block. |

#### PNAddMessageActionRequest

| Parameter | Description |
| --- | --- |
| `type` *Type: NSString | Message action type. Maximum `15` characters. |
| `value` *Type: NSString | Message action value. |
| `channel` *Type: NSString | Channel name of the target message. |
| `messageTimetoken` *Type: NSNumber | Timetoken of the target message. |

### Sample code

```objectivec
PNAddMessageActionRequest *request = [PNAddMessageActionRequest requestWithChannel:@"chat"
                                                                  messageTimetoken:@(1234567890)];
request.type = @"reaction";
request.value = @"smile";

[self.client addMessageActionWithRequest:request completion:^(PNAddMessageActionStatus *status) {
    if (!status.isError) {
        /**
         * Message action successfully added.
         * Created message action information available here: status.data.action
         */
    } else {
        if (status.statusCode == 207) {
            // Message action has been added, but event not published.
        } else {
            /**
             * Handle add message action error. Check 'category' property to find out possible
             * issue because of which request did fail.
             *
             * Request can be resent using: [status retry]
             */
        }
    }
}];
```

### Response

Response objects returned by the client when the add message action API is used:

```objectivec
@interface PNAddMessageActionData : PNServiceData

// Added message action.
@property (nonatomic, nullable, readonly, strong) PNMessageAction *action;

@end

@interface PNAddMessageActionStatus : PNAcknowledgmentStatus

// Add message action request processed information.
@property (nonatomic, readonly, strong) PNAddMessageActionData *data;

@end
```

## Add message action (builder pattern)

:::warning Requires Message Persistence
Enable Message Persistence for your key in the [Admin Portal](https://admin.pubnub.com/) as described in the [support article](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-).
:::

Add an action to a published message. The response includes the added action.

### Method(s)

Use this Cocoa method:

```objectivec
addMessageAction()
    .channel(NSString *)
    .messageTimetoken(NSNumber *)
    .type(NSString *)
    .value(NSString *)
    .performWithCompletion(nullable PNAddMessageActionCompletionBlock);
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: NSString | Channel name of the target message. |
| `messageTimetoken` *Type: NSNumber | Timetoken of the target message. |
| `type` *Type: NSString | Message action type. |
| `value` *Type: NSString | Message action value. |
| `block`Type: PNAddMessageActionCompletionBlock | Completion block. |

### Sample code

```objectivec
self.client.addMessageAction()
    .channel(@"chat")
    .messageTimetoken(@(1234567890))
    .type(@"reaction")
    .value(@"smile")
    .performWithCompletion(^(PNAddMessageActionStatus *status) {
        if (!status.isError) {
            /**
             * Message action successfully added.
             * Created message action information available here: status.data.action
             */
        } else {
            if (status.statusCode == 207) {
                // Message action has been added, but event not published.
            } else {
                /**
                 * Handle add message action error. Check 'category' property to find out possible
                 * issue because of which request did fail.
                 *
                 * Request can be resent using: [status retry]
                 */
            }
        }
    });
```

### Response

Response objects returned by the client when the add message action API is used:

```objectivec
@interface PNAddMessageActionData : PNServiceData

// Added message action.
@property (nonatomic, nullable, readonly, strong) PNMessageAction *action;

@end

@interface PNAddMessageActionStatus : PNAcknowledgmentStatus

// Add message action request processed information.
@property (nonatomic, readonly, strong) PNAddMessageActionData *data;

@end
```

## Remove message action

:::warning Requires Message Persistence
Enable Message Persistence for your key in the [Admin Portal](https://admin.pubnub.com/) as described in the [support article](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-).
:::

Remove a previously added action from a published message. The response is empty.

### Method(s)

Use this Cocoa method:

```objectivec
- (void)removeMessageActionWithRequest:(PNRemoveMessageActionRequest *)request
                            completion:(nullable PNRemoveMessageActionCompletionBlock)block;
```

| Parameter | Description |
| --- | --- |
| `request` *Type: [PNRemoveMessageActionRequest](#pnremovemessageactionrequest) | Request containing the message action to remove. |
| `block`Type: PNRemoveMessageActionCompletionBlock | Completion block. |

#### PNRemoveMessageActionRequest

| Parameter | Description |
| --- | --- |
| `actionTimetoken` *Type: NSNumber | Timetoken of the message action to remove. |
| `channel` *Type: NSString | Channel name of the target message. |
| `messageTimetoken` *Type: NSNumber | Timetoken of the target message. |

### Sample code

```objectivec
PNRemoveMessageActionRequest *request = [PNRemoveMessageActionRequest requestWithChannel:@"chat"
                                                                        messageTimetoken:@(1234567890)];
request.actionTimetoken = @(1234567891);

[self.client removeMessageActionWithRequest:request
                                 completion:^(PNAcknowledgmentStatus *status) {

    if (!status.isError) {
        // Message action successfully removed.
    } else {
        /**
         * Handle remove message action error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: [status retry]
         */
    }
}];
```

### Response

```objectivec
@interface PNErrorData : PNServiceData

// Stringified error information.
@property (nonatomic, readonly, strong) NSString *information;

@end

@interface PNAcknowledgmentStatus : PNErrorStatus

// Whether status object represent error or not.
@property (nonatomic, readonly, assign, getter = isError) BOOL error;

// Additional information related to error status object.
@property (nonatomic, readonly, strong) PNErrorData *errorData;

@end
```

## Remove message action (builder pattern)

:::warning Requires Message Persistence
Enable Message Persistence for your key in the [Admin Portal](https://admin.pubnub.com/) as described in the [support article](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-).
:::

Remove a previously added action from a published message. The response is empty.

### Method(s)

```objectivec
removeMessageAction()
    .channel(NSString *)
    .messageTimetoken(NSNumber *)
    .actionTimetoken(NSNumber *)
    .performWithCompletion(nullable PNRemoveMessageActionCompletionBlock);
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: NSString | Channel name of the target message. |
| `messageTimetoken` *Type: NSNumber | Timetoken of the target message. |
| `actionTimetoken` *Type: NSNumber | Timetoken of the message action to remove. |
| `block`Type: PNRemoveMessageActionCompletionBlock | Completion block. |

### Sample code

```objectivec
self.client.removeMessageAction()
    .channel("chat")
    .messageTimetoken(@(1234567890))
    .actionTimetoken(@(1234567891))
    .performWithCompletion(^(PNCreateSpaceStatus *status) {
        if (!status.isError) {
            // Message action successfully removed.
        } else {
            /**
             * Handle remove message action error. Check 'category' property to find out possible
             * issue because of which request did fail.
             *
             * Request can be resent using: [status retry]
             */
        }
    });
```

### Response

```objectivec
@interface PNErrorData : PNServiceData

// Stringified error information.
@property (nonatomic, readonly, strong) NSString *information;

@end

@interface PNAcknowledgmentStatus : PNErrorStatus

// Whether status object represent error or not.
@property (nonatomic, readonly, assign, getter = isError) BOOL error;

// Additional information related to error status object.
@property (nonatomic, readonly, strong) PNErrorData *errorData;

@end
```

## Get message actions

:::warning Requires Message Persistence
Enable Message Persistence for your key in the [Admin Portal](https://admin.pubnub.com/) as described in the [support article](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-).
:::

Get a list of message actions in a channel. The response sorts actions by the action timetoken in ascending order.

### Method(s)

Use this Cocoa method:

```objectivec
- (void)fetchMessagesActionsWithRequest:(PNFetchMessagesActionsRequest *)request
                             completion:(PNFetchMessageActionsCompletionBlock)block;
```

| Parameter | Description |
| --- | --- |
| `request` *Type: [PNFetchMessageActionsRequest](#pnfetchmessageactionsrequest) | Request with parameters to fetch message actions. |
| `block` *Type: PNFetchMessageActionsCompletionBlock | Completion block. |

#### PNFetchMessageActionsRequest

| Parameter | Description |
| --- | --- |
| `start` *Type: NSNumber | Message action timetoken for the start of the range (exclusive). |
| `end` *Type: NSNumber | Message action timetoken for the end of the range (inclusive). |
| `limit` *Type: NSUInteger | Number of message actions to return. |
| `channel` *Type: NSString | Channel name to list message actions for. |

### Sample code

```objectivec
PNFetchMessageActionsRequest *request = [PNFetchMessageActionsRequest requestWithChannel:@"chat"];
request.start = @(1234567891);
request.limit = 200;

[self.client fetchMessageActionsWithRequest:request
                                 completion:^(PNFetchMessageActionsResult *result,
                                              PNErrorStatus *status) {

    if (!status.isError) {
        /**
         * Message actions successfully fetched.
         * Result object has following information:
         *     result.data.actions - list of message action instances
         *     result.data.start - fetched messages actions time range start (oldest message
         *         action timetoken).
         *     result.data.end - fetched messages actions time range end (newest action timetoken).
         */
    } else {
        /**
         * Handle fetch message actions error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: [status retry]
         */
    }
}];
```

### Response

Response objects which is returned by client when `fetch message reactions` Message Reaction API is used:

```objectivec
@interface PNFetchMessageActionsData : PNServiceData

// List of fetched messages actions.
@property (nonatomic, readonly, strong) NSArray<PNMessageAction *> *actions;

/**
 * Fetched messages actions time range start (oldest message reaction timetoken).
 *
 * This timetoken can be used as 'start' value to fetch older messages actions.
 */
@property (nonatomic, readonly, strong) NSNumber *start;

// Fetched messages actions time range end (newest action timetoken).
@property (nonatomic, readonly, strong) NSNumber *end;

@end

@interface PNFetchMessageActionsResult : PNResult

// Fetch message reactions request processed information.
@property (nonatomic, readonly, strong) PNFetchMessageActionsData *data;

@end
```

Error response which is used in case of Message Reaction API call failure:

```objectivec
@interface PNErrorData : PNServiceData

// Stringified error information.
@property (nonatomic, readonly, strong) NSString *information;

@end

@interface PNErrorStatus : PNStatus

// Whether status object represent error or not.
@property (nonatomic, readonly, assign, getter = isError) BOOL error;

// Additional information related to error status object.
@property (nonatomic, readonly, strong) PNErrorData *errorData;

@end
```

## Get Message Reactions (builder pattern)

:::warning Requires Message Persistence
This method requires that Message Persistence 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/).
:::

Get a list of message reactions in a `channel`. Returns a list of actions sorted by the action's timetoken in ascending order.

### Method(s)

To Get Message Reactions you can use the following method(s) in the Cocoa SDK:

```objectivec
fetchMessageActions()
    .channel(NSString *)
    .start(NSNumber *)
    .end(NSNumber *)
    .limit(NSUInteger)
    .performWithCompletion(PNFetchMessageActionsCompletionBlock);
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: NSString | Name of channel from which list of messages `actions` should be retrieved. |
| `start`Type: NSNumber | `Message reaction` timetoken denoting the start of the range requested. Return values will be less than start. |
| `end`Type: NSNumber | `Message reaction` timetoken denoting the end of the range requested. Return values will be greater than or equal to end. |
| `limit`Type: NSUInteger | Number of message reactions to return in response. |
| `block` *Type: PNFetchMessageActionsCompletionBlock | `Fetch message reactions` request completion `block`. |

### Sample code

```objectivec
self.client.fetchMessageActions()
    .channel(@"chat")
    .start(@(1234567891))
    .limit(200)
    .performWithCompletion(^(PNFetchMessageActionsResult *result,
                             NErrorStatus *status) {

        if (!status.isError) {
            /**
             * Message reaction successfully added.
             * Result object has following information:
             *     result.data.actions - list of message reaction instances
             *     result.data.start - fetched messages actions time range start (oldest message
             *         action timetoken).
             *     result.data.end - fetched messages actions time range end (newest action timetoken).
             */
        } else {
            /**
             * Handle fetch message reactions error. Check 'category' property to find out possible
             * issue because of which request did fail.
             *
             * Request can be resent using: [status retry]
             */
        }
    });
```

### Response

Response objects which is returned by client when `fetch message reactions` Message Reaction API is used:

```objectivec
@interface PNFetchMessageActionsData : PNServiceData

// List of fetched messages actions.
@property (nonatomic, readonly, strong) NSArray<PNMessageAction *> *actions;

/**
 * Fetched messages actions time range start (oldest message action timetoken).
 *
 * This timetoken can be used as 'start' value to fetch older messages actions.
 */
@property (nonatomic, readonly, strong) NSNumber *start;

// Fetched messages actions time range end (newest action timetoken).
@property (nonatomic, readonly, strong) NSNumber *end;

@end

@interface PNFetchMessageActionsResult : PNResult

// Fetch message actions request processed information.
@property (nonatomic, readonly, strong) PNFetchMessageActionsData *data;

@end
```

### Error response

```objectivec
@interface PNErrorData : PNServiceData

// Stringified error information.
@property (nonatomic, readonly, strong) NSString *information;

@end

@interface PNErrorStatus : PNStatus

// Whether status object represent error or not.
@property (nonatomic, readonly, assign, getter = isError) BOOL error;

// Additional information related to error status object.
@property (nonatomic, readonly, strong) PNErrorData *errorData;

@end
```

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