---
source_url: https://www.pubnub.com/docs/sdks/swift/api-reference/storage-and-playback
title: Message Persistence API for Swift Native SDK
updated_at: 2026-06-01T12:05:58.410Z
sdk_name: PubNub Swift SDK
sdk_version: 10.1.6
---

> 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 Persistence API for Swift Native SDK

PubNub Swift SDK, use the latest version: 10.1.6

Install:

```bash
Add PubNub via Swift Package Manager or CocoaPods@10.1.6
```

Message Persistence gives you real-time access to the history of messages published to PubNub. Each message is timestamped to the nearest 10 nanoseconds and stored across multiple availability zones in several geographic locations. You can encrypt stored messages with AES-256 so they are not readable on PubNub’s network. For details, see [Message Persistence](https://www.pubnub.com/docs/general/storage).

You control how long messages are stored through your account’s retention policy. Options include: 1 day, 7 days, 30 days, 3 months, 6 months, 1 year, or Unlimited.

You can retrieve the following:

* Messages
* Message reactions
* Files (using the File Sharing API)

## Fetch history

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

Fetch historical messages from one or more channels. Use `includeMessageActions` to include message actions.

It's possible to control how messages are returned and in what order.

* If you specify only the `start` parameter (without `end`), you receive messages older than the `start` timetoken.
* If you specify only the `end` parameter (without `start`), you receive messages from that `end` timetoken and newer.
* If you specify both `start` and `end`, you receive messages between those timetokens (inclusive of `end`).

This function returns up to 100 messages on a single channel, or 25 per channel on up to 500 channels. To page, iteratively update the `start` timetoken.

### Method(s)

Use the following method(s) in the Swift SDK:

```swift
func fetchMessageHistory(
    for channels: [String],
    includeActions actions: Bool = false,
    includeMeta: Bool = false,
    includeUUID: Bool = true,
    includeMessageType: Bool = true,
    includeCustomMessageType: Bool = false,
    page: PubNubBoundedPage? = PubNubBoundedPageBase(),
    custom requestConfig: PubNub.RequestConfiguration = PubNub.RequestConfiguration(),
    completion: ((Result<(messagesByChannel: [String: [PubNubMessage]], next: PubNubBoundedPage?), Error>) -> Void)?
)
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| for | [String] | Yes |  | The list of channels to fetch history messages from. Maximum of 500 channels are allowed. |
| includeActions | Bool | Optional | `false` | If `true` any Message Actions will be included in the response. When set to `true` the method is limited to retrieving history from a single channel. |
| includeMeta | Bool | Optional | `false` | If `true` the meta properties of messages will be included in the response. |
| includeUUID | Bool | Optional | `true` | If `true` the user ID of the sender will be included in the response. |
| includeMessageType | Bool | Optional | `true` | Indicates whether to retrieve messages with PubNub message type. For more information, refer to [Retrieving Messages](https://www.pubnub.com/docs/general/storage#retrieve-messages). |
| includeCustomMessageType | Bool | Optional | `false` | Indicates whether to retrieve messages with the custom message type. For more information, refer to [Retrieving Messages](https://www.pubnub.com/docs/general/storage#retrieve-messages). |
| page | PubNubBoundedPage? | Optional | `PubNubBoundedPageBase()` | The paging object used for pagination. It allows you to specify a range of messages to retrieve based on specific time bounds. Set `limit` to control the number of results per page. Maximum value is 100 for a single channel, 25 for multiple channels, and 25 when `includeActions` is `true`. |
| custom | PubNub.RequestConfiguration | Optional | `PubNub.RequestConfiguration()` | An object that allows for per-request customization of PubNub configuration or network session. For more information, refer to the [Request Configuration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration) section. |
| completion | ((Result<(messagesByChannel: | Optional | `nil` | The async `Result` of the method call. |

:::note Truncated response
If truncated, a `next` property is returned with additional parameters. Make iterative calls adjusting parameters.
:::

#### Completion handler result

##### Success

A dictionary of channels mapped to their message lists, and the next page cursor when available.

```swift
public protocol PubNubMessage {

  /// The message sent on the channel
  var payload: JSONCodable { get set }

  /// Message reactions associated with this message
  var actions: [PubNubMessageAction] { get set }

  /// Message sender identifier
  var publisher: String? { get set }

  /// The channel for which the message belongs
  var channel: String { get }

  /// The channel group or wildcard subscription match (if exists)
  var subscription: String? { get }

  /// Timetoken for the message
  var published: Timetoken { get set }

  /// Meta information for the message
  var metadata: JSONCodable? { get set }

  /// The type of message that was received
  var messageType: PubNubMessageType { get set }

  /// A user-provided custom message type
  var customMessageType: String? { get set }

  /// Message actions associated with this message
  var actions: [PubNubMessageAction] { get set }

  /// The channel for which the message belongs
  var channel: String { get }

  /// Timetoken for the message
  var published: Timetoken { get set }

  /// Meta information for the message
  var metadata: JSONCodable? { get set }
}
```

```swift
public protocol PubNubBoundedPage {

  /// The start value for the next set of remote data
  var start: Timetoken? { get }

  /// The bounded end value that will be eventually fetched to
  var end: Timetoken? { get }

  /// The previous limiting value (if any)
  var limit: Int? { get }
}
```

##### Failure

An error describing the failure.

### Sample code

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

Retrieve the last message on a channel:

```swift
import PubNubSDK

// Initializes a PubNub object with the configuration
let pubnub = PubNub(
  configuration: PubNubConfiguration(
    publishKey: "demo",
    subscribeKey: "demo",
    userId: "myUniqueUserId"
  )
)

// Retrieve messages from a channel
pubnub.fetchMessageHistory(for: ["my_channel"]) { result in
  switch result {
  case let .success(response):
    if let myChannelMessages = response.messagesByChannel["my_channel"] {
      // Iterating over each message in the channel and printing its payload
      myChannelMessages.forEach { historicalMessage in
        print("Message payload: \(historicalMessage.payload)")
      }
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

### Other examples

#### Retrieve messages newer or equal than a given timetoken

```swift
// Retrieve messages that are newer or equal to a specific timetoken
pubnub.fetchMessageHistory(
  for: ["my_channel"],
  page: PubNubBoundedPageBase(end: 13406746780720711)
) { result in
  switch result {
  case let .success(response):
    if let myChannelMessages = response.messagesByChannel["my_channel"] {
      // Iterating over each message in the channel and printing its payload
      myChannelMessages.forEach { historicalMessage in
        print("Message payload: \(historicalMessage.payload)")
      }
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

#### Retrieve messages older than a specific timetoken

```swift
// Retrieve messages older than a specific timetoken (exclusive).
// Exclusive means that the message associated with the `13406746780720711` timetoken will be excluded from the result.
pubnub.fetchMessageHistory(
  for: ["my_channel"],
  page: PubNubBoundedPageBase(start: 13406746780720711)
) { result in
  switch result {
  case let .success(response):
    if let myChannelMessages = response.messagesByChannel["my_channel"] {
      // Iterating over each message in the channel and printing its payload
      myChannelMessages.forEach { historicalMessage in
        print("Message payload: \(historicalMessage.payload)")
      }
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

#### Retrieve the last 10 messages on channelSwift, otherChannel, and myChannel

```swift
// Retrieve messages from multiple channels with a limit on the number of messages returned
pubnub.fetchMessageHistory(
  for: ["channelSwift", "otherChannel", "myChannel"],
  page: PubNubBoundedPageBase(limit: 10)
) { result in
  switch result {
  case let .success(response):
    response.messagesByChannel.forEach { channel, messages in
      print("Channel `\(channel)` has the following messages: \(messages)")
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

#### Retrieve messages and their metadata

```swift
// Retrieve messages from a channel with metadata
pubnub.fetchMessageHistory(
  for: ["my_channel"],
  includeMeta: true
) { result in
  switch result {
  case let .success(response):
    if let myChannelMessages = response.messagesByChannel["my_channel"] {
      // Iterating over each message in the channel to print its payload and metadata
      myChannelMessages.forEach { message in
        print("Message sent at \(message.published):")
        print("Payload: \(message.payload)")
        print("Metadata: \(String(describing: message.metadata))")
      }
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

#### Retrieve messages and their message action data

```swift
// Retrieve messages from a channel with actions
pubnub.fetchMessageHistory(
  for: ["my_channel"],
  includeActions: true
) { result in
  switch result {
  case let .success(response):
    if let myChannelMessages = response.messagesByChannel["my_channel"] {
      myChannelMessages.forEach { message in
        print("Message sent at \(message.published):")
        print("Actions: \(message.actions)")
      }
    }
    if let nextPage = response.next {
      print("The next page used for pagination: \(nextPage)")
    }
  case let .failure(error):
    print("Failed History Fetch Response: \(error.localizedDescription)")
  }
}
```

## Delete messages from history

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

Removes the messages from the history of a specific channel.

:::note Required setting
Enable Delete-From-History in key settings and initialize with a secret key.
:::

### Method(s)

To `Delete Messages from History` you can use the following method(s) in the Swift SDK.

```swift
func deleteMessageHistory(
    from channel: String,
    start: Timetoken? = nil,
    end: Timetoken? = nil,
    custom requestConfig: PubNub.RequestConfiguration = PubNub.RequestConfiguration(),
    completion: ((Result<Void, Error>) -> Void)?
)
```

| Parameter | Description |
| --- | --- |
| `from` *Type: StringDefault: n/a | The channel to delete the messages from. |
| `start`Type: `timetoken`?Default: `nil` | `timetoken` delimiting the start of time slice (inclusive) to delete messages from. |
| `end`Type: `timetoken`?Default: `nil` | `timetoken` delimiting the end of time slice (exclusive) to delete messages from. |
| `custom`Type: [PubNub.RequestConfiguration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration)Default: `PubNub.RequestConfiguration()` | An object that allows for per-request customization of PubNub configuration or network session. For more information, refer to the [Request Configuration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration) section. |
| `completion`Type: `((Result<Void, Error>) -> Void)?`Default: `nil` | The async `Result` of the method call |

#### Completion handler result

##### Success

A `Void` indicating a success.

##### Failure

An `Error` describing the failure.

### Sample code

```swift
// Delete all messages from a channel
pubnub.deleteMessageHistory(
  from: "my_channel"
) { result in
  switch result {
  case .success:
    print("The message deletion was successful")
  case let .failure(error):
    print("Failed Message Deletion Response: \(error.localizedDescription)")
  }
}
```

### Other examples

#### Delete specific message from history

```swift
// Delete a specific message from a channel
pubnub.deleteMessageHistory(
  from: "my_channel",
  start: 15526611838554309,
  end: 15526611838554310
) { result in
  switch result {
  case .success:
    print("The message deletion was successful")
  case let .failure(error):
    print("Failed Message Deletion Response: \(error.localizedDescription)")
  }
}
```

## Message counts

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

Return the number of messages published since the given time; the count is messages with timetoken ≥ the provided value.

:::note Unlimited message retention
For keys with unlimited message retention enabled, this method considers only messages published in the last 30 days.
:::

### Method(s)

You can use the following method(s) in the Swift SDK:

```swift
func messageCounts(
    channels: [String: Timetoken],
    custom requestConfig: PubNub.RequestConfiguration = PubNub.RequestConfiguration(),
    completion: ((Result<[String: Int], Error>) -> Void)?
)
```

| Parameter | Description |
| --- | --- |
| `channels` *Type: [String: `timetoken`]Default: n/a | The map of channels and the `timetoken` to get the message count for. |
| `custom`Type: [PubNub.RequestConfiguration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration)Default: `PubNub.RequestConfiguration()` | An object that allows for per-request customization of PubNub configuration or network session. For more information, refer to the [Request Configuration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration) section. |
| `completion`Type: `((Result<[String: Int], Error>) -> Void)?`Default: `nil` | The async `Result` of the method call. |

```swift
func messageCounts(
    channels: [String],
    timetoken: Timetoken = 1,
    custom requestConfig: PubNub.RequestConfiguration = PubNub.RequestConfiguration(),
    completion: ((Result<[String: Int], Error>) -> Void)?
)
```

| Parameter | Description |
| --- | --- |
| `channels` *Type: [String]Default: n/a | The list of channels to get message counts for. |
| `timetoken`Type: `timetoken`Default: `1` | The `timetoken` for all channels in the list to get message counts for. |
| `custom`Type: [PubNub.RequestConfiguration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration)Default: `PubNub.RequestConfiguration()` | An object that allows for per-request customization of PubNub configuration or network session. For more information, refer to the [Request Configuration](https://www.pubnub.com/docs/sdks/swift/api-reference/configuration#request-configuration) section. |
| `completion`Type: `((Result<[String: Int], Error>) -> Void)?`Default: `nil` | The async `Result` of the method call. |

#### Completion handler result

##### Success

A `Dictionary` of channels mapped to their respective message count.

##### Failure

An `Error` describing the failure.

### Sample code

```swift
// Retrieve the message count for a channel
pubnub.messageCounts(channels: ["my_channel"]) { result in
  switch result {
  case let .success(messageCountByChannel):
    if let myChannelCount = messageCountByChannel["my_channel"] {
      print("The current message count for `my_channel` is \(myChannelCount)")
    }
  case let .failure(error):
    print("Failed Message Count Response: \(error.localizedDescription)")
  }
}
```

### Other examples

#### Retrieve message counts for multiple channels with the same timetoken 15526611838554310

```swift
// Retrieve the message count for multiple channels
pubnub.messageCounts(
  channels: ["my_channel", "other_channel", "their_channel"],
  timetoken: 15526611838554310
) { result in
  switch result {
  case let .success(messageCountByChannel):
    messageCountByChannel.forEach { channel, messageCount in
      print("The current message count for `\(channel)` is \(messageCount)")
    }
  case let .failure(error):
    print("Failed Message Count Response: \(error.localizedDescription)")
  }
}
```

#### Retrieve message counts for multiple channels with different timetokens

```swift
// Retrieve the message count for multiple channels with different timetokens
pubnub.messageCounts(
  channels: [
    "my_channel": 15526611838554309,
    "other_channel": 15526611838554310,
    "their_channel": 1
  ]
) { result in
  switch result {
  case let .success(messageCountByChannel):
    messageCountByChannel.forEach { channel, messageCount in
      print("The current message count for `\(channel)` is \(messageCount)")
    }
  case let .failure(error):
    print("Failed Message Count Response: \(error.localizedDescription)")
  }
}
```

## 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.
* **Message** - A unit of data transmitted between clients or between a client and a server in PubNub, containing information such as text, binary data, or structured data formats like JSON. Messages are sent over channels and can be tracked for delivery and read status.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.