---
source_url: https://www.pubnub.com/docs/general/messages/actions
title: Message Actions
updated_at: 2026-06-04T11:10:12.661Z
---

> 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

Message actions add lightweight metadata to messages without changing the content. Use them for:

* Read receipts
* Delivery receipts
* Emoji reactions (message actions)

Each action has a `type` and a `value`, both strings. Actions reference a message by a timetoken. Use your own emoji library; PubNub SDKs do not include one.

Parameter names vary by SDK. Examples: `messageTimetoken`, `message_timetoken`.

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

:::note Limits
The `type` and `value` properties have no individual size limits. The overall message action request is subject to the standard PubNub API limit of 32 KiB for the request path or body.
:::

## Add message actions

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

### JavaScript

```javascript
pubnub.addMessageAction(
  {
    channel: 'chats.room1',
    messageTimetoken: '15610547826970040',
    action: {
      type: 'reaction',
      value: 'smiley_face',
    }
  },
  function(status, response) {
    console.log(status, response);
  }
);
```

### Swift

```swift
extension MyAppMessageAction: MessageAction {}
let action = MyAppMessageAction(type: "reaction", value: "smiley_face")

pubnub.addMessageAction(
  channel: "chats.room1",
  message: action,
  messageTimetoken: 15_610_547_826_969_050
) { result in
  switch result {
    case let .success(response):
      print("Successfully Message Reaction Add Response: \(response)")

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

### Objective-C

```objectivec
PNAddMessageActionRequest *request =
    [PNAddMessageActionRequest requestWithChannel:@"chats.room1"
      messageTimetoken:@(1234567890)];

request.type = @"reaction";
request.value = @"smile";

[self.pubnub addMessageActionWithRequest:request
  completion:^(PNAddMessageActionStatus *status) {

  if (!status.isError) {

  }
  else {

  }
}];
```

### Java

```java
pubnub.addMessageAction().channel("chats.room1")
  .messageAction(new PNMessageAction()
    .setType("reaction")
    .setValue("smiley_face")
    .setMessageTimetoken(15701761818730000L)
  )
  .async(result -> {
      result.onSuccess(res -> {
              System.out.println(res.getType());
              System.out.println(res.getValue());
              System.out.println(res.getUuid());
              System.out.println(res.getActionTimetoken());
              System.out.println(res.getMessageTimetoken());
      }).onFailure(exception -> {
          exception.printStackTrace();
      });
  });
```

### C#

```csharp
pubnub.AddMessageAction()
  .Channel("chats.room1")
  .MessageTimetoken(5610547826969050)
  .Action(new PNMessageAction { Type = "reaction", Value = "smiley_face" })
  .Execute(new PNAddMessageActionResultExt((result, status) =>
  {

  }));
```

### Python

```python
msg_action = PNMessageAction()
msg_action.type = "reaction"
msg_action.value = "smiley_face"
msg_action.message_timetoken = str(int(time.time()))
pubnub.add_message_action()\
  .channel("chats.room1")\
  .message_action(msg_action)\
  .pn_async(message_action_callback)
```

## Receive message actions

To receive a message action, listen for the [event](https://www.pubnub.com/docs/general/messages/receive) type `messageAction` and [subscribe](https://www.pubnub.com/docs/general/channels/subscribe) to the channel where the action is added. Subscribe the same way you do for other events.

## Remove message actions

Remove an action from a message. The response is empty.

### JavaScript

```javascript
pubnub.removeMessageAction(
  {
    channel: 'chats.room1',
    messageTimetoken: '15610547826970040',
    actionTimetoken: '15610547826970075',
  },
  function(status, response) {

  });
```

### Swift

```swift
pubnub.removeMessageActions(
  channel: "chats.room1",
  message: 15_610_547_826_969_050,
  action: 15_610_547_826_970_051
) { result in
  switch result {
    case let .success(response):
      print("Successfully Message Action Remove Response: \(response)")

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

### Objective-C

```objectivec
PNRemoveMessageActionRequest *request =
      [PNRemoveMessageActionRequest requestWithChannel:@"chats.room1",
          messageTimetoken:@(1234567890)];

request.actionTimetoken = @(1234567891);

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

  if (!status.isError) {

  }
  else {

  }
}];
```

### Java

```java
pubnub.removeMessageAction()
  .channel("chats.room1")
  .messageTimetoken(15701761818730000L)
  .actionTimetoken(15701775691010001L)
  .async(result -> { /* check result */ });
```

### C#

```csharp
pubnub.RemoveMessageAction()
  .Channel("chats.room1")
  .MessageTimetoken(15701761818730000)
  .ActionTimetoken(15701775691010001)
  .Execute(new PNRemoveMessageActionResultExt((result, status) =>
  {

  }));
```

### Python

```python
 pubnub.remove_message_action()
        .channel('chats.room1')
        .message_timetoken(15701761818730000) # Some message timetoken
        .action_timetoken(15701775691010001) # Some action timetoken
        .pn_async(message_action_callback)
```

## Retrieve actions

Use the History with Actions API to get messages with their actions. You can also get only actions for a time window. This helps you catch up after the app was offline. The API returns actions sorted by action timetoken, oldest first.

:::note Offline message actions
You can add actions to any message, even ones published before your app went offline.
:::

###### JavaScript

```javascript
pubnub.getMessageActions(
  {
    channel: 'chats.room1',
    start: '15610547826970041',
    end: '15610547826970040',
    limit: 100,
  },
  function(status, response) {
    console.log(status, response);
  }
);
```

###### Swift

```swift
pubnub.fetchMessageActions(
  channel: "chats.room1") { result in
    switch result {
    case let .success(response):
      print("Successfully Message Action Fetch Response: \(response)")

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

###### Objective-C

```objectivec
PNFetchMessageActionsRequest *request =
    [PNFetchMessageActionsRequest requestWithChannel:@"chats.room1"];

request.start = @(1234567891);
request.limit = 100;

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

  if (!status.isError) {

  }
  else {

  }
}];
```

###### Java

```java
pubnub.getMessageActions()
  .channel("chats.room1")
  .async(result -> {
      result.onSuccess(res -> {
              List<PNMessageAction> actions = res.getActions();
              for (PNMessageAction action : actions) {
                  System.out.println(action.getType());
                  System.out.println(action.getValue());
                  System.out.println(action.getUuid());
                  System.out.println(action.getActionTimetoken());
                  System.out.println(action.getMessageTimetoken());
              }
      }).onFailure(exception -> {
          exception.printStackTrace();
      });
  });
```

###### C#

```csharp
pubnub.GetMessageActions()
  .Channel("chats.room1")
  .Execute(new PNGetMessageActionsResultExt((result, status) =>
  {

  }));
```

**Return Type**: `PNGetMessageActionsResult`

```json
{
  "MessageActions":[{
    "MessageTimetoken":15610547826969050,
    "Action":{
      "type":"reaction",
        "value":"smiley_face"
    },
    "Uuid":"pn-5903a053-592c-4a1e-8bfd-81d92c962968",
    "ActionTimetoken":15717253483027901
  }],
  "More": {
    "Start": 15610547826970050,
    "End": 15645905639093361,
    "Limit": 2
  }
}
```

###### Python

```python
pubnub.get_message_actions()
        .channel('chats.room1')
        .start(15901706735798837) # Some start timetoken or None
        .end(15901706735798836) # Some end timetoken or None
        .pn_async(message_action_callback)
```

## Delete messages

Enable Delete-From-History requests in the [Admin Portal](https://admin.pubnub.com). In this example, the `start` and `end` timetoken values differ by 1 (last digit). This deletes the message at the `end` timetoken.

### JavaScript

```javascript
pubnub.deleteMessages(
  {
    channels: 'chats.room1',
    start: "15526611838554309",
    end: "15526611838554310",
  },
  function (status, response) {
    console.log(status, response);
  }
);
```

### Swift

```swift
pubnub.deleteMessageHistory(
  from: "chats.room1",
  start: 15526611838554309,
  end: 15526611838554310
) { result in
  switch result {
    case let .success(response):
      print("Successful Message Deletion Response: \(response)")

    case let .failure(error):
      print("Failed Message Deletion Response: \(error.localizedDescription)")
  }
}
```

### Objective-C

```objectivec
[self.client deleteMessagesFromChannel:@"chats.room1"
    start:@15526611838554309 end:@15526611838554310
    withCompletion:^(PNAcknowledgmentStatus *status) {

  if (status.isError) {
    // handle error condtion
  }
  else {
    // confirm delete success
  }
}];
```

### Java

```java
pubnub.deleteMessages()
  .channels(Arrays.asList("chats.room1"))
  .start(15526611838554309L)
  .end(15526611838554310L)
  .async(result -> { /* check result */ });
```

### C#

```csharp
pubnub.DeleteMessages().Channel("chats.room1")
  .Start(15526611838554309)
  .End(15526611838554310)
  .Execute(new PNDeleteMessageResultExt((result, status) => {
      if (status != null && status.Error) {
        Console.WriteLine(status.ErrorData.Information);
      }
      else if (result != null) {
        Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(result));
      }
    }
  ));
```

### Python

```python
envelope = PubNub(pnconf).delete_messages().channel('chats.room1') \
  .start(15526611838554309) \
  .end(15526611838554310) \
  .sync()
```

### Bulk message delete

You can delete multiple messages or all messages in a channel.

| Parameters | Behavior |
| --- | --- |
| start & end | Delete messages between those timetokens (only one message at the end timetoken if values differ by 1) |
| start only | Delete all messages before (not at) that timetoken |
| end only | Delete all messages after (and at) that timetoken |
| none | Delete all messages |

:::warning No undo option
Deletions are permanent. Verify the timetoken range before sending the request.
:::

## Terms in this document

* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.
