---
source_url: https://www.pubnub.com/docs/data-storage/message-history/delete-messages-from-history
title: Delete messages from history
updated_at: 2026-09-30T07:20:08.000Z
---

# Delete messages from history

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

This guide shows you how to delete messages from [Message Persistence](https://www.pubnub.com/docs/data-storage/message-history/overview.md) storage. You can remove all messages between two timetokens or target a single message by its publish timetoken.

Three things must be in place before you call the delete API:

* **Delete-From-History enabled.** Open the [Admin Portal](https://admin.pubnub.com), go to your keyset settings, and turn on **Enable Delete-From-History**. The delete API returns an error if this toggle is off.
* **Secret key.** The PubNub client making the delete call must be initialized with your secret key. Use it only in server-side code. Never expose the secret key to client devices. For initialization steps, see [Application setup](https://www.pubnub.com/docs/getting-started/quickstart.md).
* **delete permission (if Access Manager is on).** If Access Manager is enabled on your keyset, the token used for the request must grant `delete` on the target channel. See [Access control](https://www.pubnub.com/docs/security/access-control/overview.md).

:::warning No undo
Deletion is permanent. There is no recovery path after a successful call, so verify the timetoken range before you send the request.
:::

## Delete a range of messages

Pass `start` and `end` timetokens to remove all messages between two points in time. The call deletes the message at `end` but not the message at `start`, whichever of the two values is larger. For example, if a channel has messages at timetokens `T - 1`, `T`, and `T + 1`:

| `start` | `end` | Deleted | Kept |
| --- | --- | --- | --- |
| `T - 1` | `T + 1` | `T`, `T + 1` | `T - 1` |
| `T + 1` | `T - 1` | `T - 1`, `T` | `T + 1` |

### JavaScript

```javascript
try {
  const result = await pubnub.deleteMessages({
    channel: 'ch1',
    start: 'replace-with-start-timetoken',
    end: 'replace-with-end-timetoken',
  });
  console.log('Messages deleted successfully:', result);
} catch (error) {
  console.error(`Messages delete failed: ${error}`);
}
```

### Python

```python
envelope = PubNub(pnconf).delete_messages() \
    .channel("my-ch") \
    .start(123) \
    .end(456) \
    .sync()
```

### Swift

```swift
let startDate = NSNumber(value: (15101397027611671 as CUnsignedLongLong))
let endDate = NSNumber(value: (15101397427611671 as CUnsignedLongLong))
self.client.deleteMessagesFromChannel("channel", start: startDate, end: endDate, withCompletion: { (status) in

    if !status.isError {
        // Messages within specified time frame has been removed.
    } else {
        /**
         * Handle message history download error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: status.retry()
         */
    }
})
```

### Objective-C

```objectivec
[self.client deleteMessagesFromChannel:@"channel" start:@15101397027611671 end:@15101397427611671
                        withCompletion:^(PNAcknowledgmentStatus *status) {

    if (!status.isError) {
        // Messages within specified time frame has been removed.
    } else {
        /**
         * Handle message history download error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: [status retry];
         */
    }
}];
```

### Java

```java
pubNub.deleteMessages()
        .channels(Arrays.asList("channel_1", "channel_2"))
        .start(1460693607379L)
        .end(1460893617271L)
        .async(result -> { /* check result */ });
```

### C#

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = new Pubnub(pnConfiguration);
        
PNResult<PNDeleteMessageResult> delMsgResponse = await pubnub.DeleteMessages()
    .Channel("history_channel")
    .Start(15088506076921021)
    .End(15088532035597390)
    .ExecuteAsync();

PNDeleteMessageResult delMsgResult = delMsgResponse.Result;
PNStatus status = delMsgResponse.Status;

if (status != null && status.Error)
{
    //Check for any error
    Console.WriteLine(status.ErrorData.Information);
}
else if (delMsgResult != null)
{
    //Expect empty object
    Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(delMsgResult));
}
```

### Kotlin

```kotlin
pubnub.deleteMessages(
    channels = listOf("channel_1", "channel_2"),
    start = 1460693607379L,
    end = 1460893617271L
).async { result ->
    // The deleteMessages() method does not return actionable data.
    // Be sure to check the status on the outcome of the operation

    if (result.isSuccess) {
        println("Successfully deleted messages.")
    } else {
        println("Error deleting messages: ${result.exceptionOrNull()?.message}")
    }
}
```

### Dart

```dart
await pubnub
  .channel('channel-name')
  .messages(
    from: Timetoken(BigInt.parse('123345')),
    to: Timetoken(BigInt.parse('123538293')),
  )
  .delete();
```

## Delete a specific message

To target a single message, set `end` to its publish timetoken and `start` to that timetoken minus 1. PubNub returns the publish timetoken in the publish response. With messages at `T - 1`, `T`, and `T + 1`, this deletes only `T`. Setting `start` to the timetoken plus 1 deletes the same message.

For example, if the publish timetoken is `15526611838554310`, pass `15526611838554309` as `start` and `15526611838554310` as `end`.

### JavaScript

```javascript
try {
  const response = await pubnub.deleteMessages({
    channel: 'ch1',
    start: 'replace-with-start-timetoken',
    end: 'replace-with-end-timetoken',
  });
  console.log('delete messages response:', response);
} catch (error) {
  console.error(`delete messages failed with error: ${error}`);
}
```

### Python

```python
envelope = PubNub(pnconf).delete_messages() \
    .channel("my-ch") \
    .start(15526611838554309) \
    .end(15526611838554310) \
    .sync()
```

### Swift

```swift
let startDate = NSNumber(value: (15526611838554309 as CUnsignedLongLong))
let endDate = NSNumber(value: (15526611838554310 as CUnsignedLongLong))
self.client.deleteMessagesFromChannel("channel", start: startDate, end: endDate, withCompletion: { (status) in

    if !status.isError {
        // Messages within specified time frame has been removed.
    } else {
        /**
         * Handle message history download error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: status.retry()
         */
    }
})
```

### Objective-C

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

    if (!status.isError) {
        // Messages within specified time frame has been removed.
    } else {
        /**
         * Handle message history download error. Check 'category' property to find out possible
         * issue because of which request did fail.
         *
         * Request can be resent using: [status retry];
         */
    }
}];
```

### Java

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

### C#

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = new Pubnub(pnConfiguration);
        
PNResult<PNDeleteMessageResult> delMsgResponse = await pubnub.DeleteMessages()
    .Channel("history_channel")
    .Start(15526611838554309)
    .End(15526611838554310)
    .ExecuteAsync();

PNDeleteMessageResult delMsgResult = delMsgResponse.Result;
PNStatus status = delMsgResponse.Status;

if (status != null && status.Error)
{
    //Check for any error
    Console.WriteLine(status.ErrorData.Information);
}
else if (delMsgResult != null)
{
    //Expect empty object
    Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(delMsgResult));
}
```

### Kotlin

```kotlin
pubnub.deleteMessages(
    channels = listOf("channel_1"),
    start = 15526611838554309L,
    end = 15526611838554310L
).async { result ->
    // The deleteMessages() method does not return actionable data.
    // Be sure to check the status on the outcome of the operation

    if (result.isSuccess) {
        println("Successfully deleted messages.")
    } else {
        println("Error deleting messages: ${result.exceptionOrNull()?.message}")
    }
}
```

A PubNub timetoken exceeds the largest integer a JavaScript `Number` represents exactly, so increment or compare timetokens with an arbitrary-precision integer type such as `BigInt` rather than with plain numeric arithmetic.

:::note Effect on usage metrics
Deleting messages doesn't update usage metrics for past dates.
Changes to your stored data volume appear in the
[Admin Portal](https://admin.pubnub.com/)
within 24 hours.
:::

## Related tasks

* [Retrieve message history](https://www.pubnub.com/docs/data-storage/message-history/retrieve-message-history.md). Check what messages exist in a channel before targeting a deletion range.
* [Message Persistence](https://www.pubnub.com/docs/data-storage/message-history/overview.md). How storage, retention, and the timetoken model work.

Last updated at: 2026-09-30T07:20:08.000Z
