Message Persistence
Message Persistence allows you to store messages as they are published. The primary use case is retrieving messages that were published while a device was offline, though there are many others. You can configure message retention for specific periods or for unlimited time.
Network interruptions
The automatic reconnection mechanism handles network interruptions. See the Connection Management guide for details on retries and backoff strategies.
When a message is published, it is stored with the channel name and the message’s publish timetoken. You can use this information to retrieve, delete, or annotate messages.
You can retrieve the following:
Configuration
Enable and configure Message Persistence for your app’s keyset in the Admin Portal.
Public Admin Portal demo
Want to browse through the Admin Portal without creating an account? Explore it through the Public Demo that shows examples of most PubNub features for transport and logistics use case.
By default, Message Persistence is enabled on every newly created keyset. Testing keysets default to 7 days
retention, which determines how long messages remain in storage before deletion.
Option | Description |
---|---|
Retention | How long messages are saved. Free accounts support 1 day or 7 days. Paid accounts support higher limits. Align the message retention period with your File Sharing settings. This stores messages and files for the same duration. |
Enable Delete-From-History | A setting that lets you use API calls to delete specific messages previously stored in a channel's message history. |
Include presence events | This option includes Presence events in saved history to let you track them later on. |
Message retention
To retain a message, make sure Message Persistence is enabled for the target keyset in the Admin Portal. You may also configure the retention duration, enable Delete-From-History, and choose whether to retain Presence events. Once configured, Message Persistence is enabled for all channels in the keyset.
Immutable message retention
Retention settings apply prospectively. Updating Message Persistence retention affects only messages published after the change.
Retrieve messages
Retrieving messages from Message Persistence is accomplished using the Message Persistence API. You can retrieve up to 100 messages for a single channel or 25 messages for multiple channels (up to 500) in a single request.
The Message Persistence API returns regular messages, file messages, and message actions. The values of the returned messageType
and custom_message_type
parameters indicate the PubNub type (integer) and your custom type (string) of a particular message, respectively. You can use it to tag messages (text messages, signals, and files) to later filter or group them.
Message Type | Description | Saved in Message Persistence |
---|---|---|
0 | Regular message | Yes |
1 | Signal | No |
2 | App Context event | No |
3 | Message Rctions event | Yes |
4 | File message | Yes |
Retrieving message actions
You can retrieve messages and their associated message actions, or you can retrieve only the message actions. Refer to Retrieve Actions for more information.
You can provide start
and end
timetokens to get messages from a specific time range. Most use cases require retrieving only the most recent messages since a given timetoken (missed messages since last online). For this, you need only provide the end
parameter with a timetoken of the last received message. The following example will retrieve the last 25 (default/max) messages on the two channels.
- JavaScript
- Swift
- Objective-C
- Java
- C#
- Python
pubnub.fetchMessages(
{
channels: ["chats.room1", "chats.room2"],
end: '15343325004275466',
count: 25 // default/max is 25 messages for multiple channels (up to 500)
},
function(status, response) {
console.log(status, response);
}
);
pubnub.fetchMessageHistory(
for: ["chats.room1", "chats.room2"],
end: "15343325004275466"
) { result in
switch result {
case let .success(response):
print("Successful History Fetch Response: \(response)")
case let .failure(error):
print("Failed History Fetch Response: \(error.localizedDescription)")
}
}
self.pubnub.history()
.channels(@[@"chats.room1", @"chats.room2"])
.end(15343325004275466).limit(25)
.performWithCompletion(^(PNHistoryResult *result, PNErrorStatus *status) {
// handle returned messages in result
});
pubNub.fetchMessages()
.channels(Arrays.asList("ch1", "ch2", "ch3"))
.async(result -> {
result.onSuccess(res -> {
final Map<String, List<PNFetchMessageItem>> channelToMessageItemsMap = res.getChannels();
final Set<String> channels = channelToMessageItemsMap.keySet();
for (final String channel : channels) {
List<PNFetchMessageItem> pnFetchMessageItems = channelToMessageItemsMap.get(channel);
for (final PNFetchMessageItem fetchMessageItem: pnFetchMessageItems) {
System.out.println(fetchMessageItem.getMessage());
System.out.println(fetchMessageItem.getMeta());
System.out.println(fetchMessageItem.getTimetoken());
}
}
}).onFailure(exception -> {
show all 18 linespubnub.FetchHistory()
.Channels(new string[] { "my_channel" })
.MaximumPerChannel(25)
.End(15343325004275466)
.Execute(new PNFetchHistoryResultExt((result, status) => {
// handle returned messages in result
}));
envelope = pubnub.fetch_messages()\
.channels(["chats.room1", "chats.room2"])\
.count(25)\
.end(15343325004275466)\
.sync()
If you need more than 25 messages, use the timetokens of returned messages to page backward in time and retrieve additional messages. You can page through a channel’s timeline recursively until you retrieve all required messages.
Parameters Used | Behavior |
---|---|
start | Retrieves messages before the start timetoken, excluding any message at that timetoken |
end | Retrieves messages after the end timetoken, including any message at that timetoken |
start & end | Retrieves messages between the start and end timetokens, excluding any message at the start timetoken and including any message at the end timetoken |
You can convert a Unix timestamp to a PubNub timetoken using the converter.
Filtering retrieved messages
There is currently no built-in server-side search functionality in the Message Persistence API to fetch only messages filtered by keywords. To filter the content of the messages, you must first retrieve them from Message Persistence and then filter them by keywords on the local client. Similarly, you can filter based on the values of the type
and custom_message_type
parameters to only show certain types of messages that you had previously, like vip-chat
or intruder-alert
.
Alternatively, you can implement a self-hosted server and use the After Publish Function to automatically send all messages to your own database and filter them on the server side.
For more information or assistance, contact support.
Delete messages from history
Message Persistence allows you to delete messages from history. You can delete a number of messages that were published between two points in time or you can delete a specific message.
Deleting messages from history is only allowed for SDK clients that have been initialized with the secret key. Each SDK provides a different method of removing messages from storage. Consult the SDK documentation for reference.
For more information on how to initialize PubNub with secret key, refer to Application Configuration.
Receive messages and signals
When a message, or signal is received by the client, it triggers a message
or signal
event, respectively. Refer to Receive Messages to learn how to act upon these events.
How messages are fetched
The following details explain how messages are retrieved from Message Persistence based on the start and end parameters.
Scenario 1
Scenario 1 retrieves messages starting with the message stored before the start timetoken parameter value and continues until it has 25 messages or hits that oldest message (whichever comes first).
Parameter | Value |
---|---|
count | 25 |
start | value provided |
end | value not provided |
Channel Timeline
oldest-message --------------- start-timetoken --------------- newest-message
[ <--------]
Scenario 2
Parameter | Value |
---|---|
count | 25 |
start | value not provided |
end | value provided |
Channel Timeline
oldest-message --------------- end-timetoken --------------- newest-message
[ <---------------------]
Scenario 3
Parameter | Value |
---|---|
count | 25 |
start | value provided |
end | value provided |
Channel Timeline
oldest-message ----- end-timetoken ----------------- start-timetoken ----- newest-message
[ <----------------------]
Get message counts
The Message Count API returns the number of messages sent after a given point in time. You can specify up to 100 channels in a single call.
Rather than retrieving lots of messages from hundreds of channels, you can get the number of missed messages and retrieve the messages later. For example, you can display the unread message count on channels that the client hasn't visited yet and retrieve those messages when the client actually visits the channel.
The Message Count API returns the number of messages sent for each channel greater than or equal to the provided timetoken. You can not specify a time range because it's only intended to give the number of messages since a given timetoken. Optionally, you can specify a different timetoken per channel or one timetoken to be applied to all channels.
Unlimited message retention
For keys with unlimited message retention enabled, this method considers only messages published in the last 30 days.
- JavaScript
- Swift
- Objective-C
- Java
- C#
- Python
pubnub.messageCounts({
channels: ["chats.room1", "chats.room2"],
channelTimetokens: ['15518041524300251']
}).then((response) => {
console.log(response)
}).catch((error) => {
// handle error
}
);
pubnub.messageCounts(
channels: ["chats.room1", "chats.room2"]),
timetoken: 15495750401727535
) { result in
switch result {
case let .success(response):
print("Successful Message Count Response: \(response)")
case let .failure(error):
print("Failed Message Count Response: \(error.localizedDescription)")
}
}
self.client.messageCounts().channels(@[@"chats.room1", @"chats.room2"])
.timetokens(@[@(15495750401727535)])
.performWithCompletion(^(PNMessageCountResult *result, PNErrorStatus *status) {
if (!status.isError) {
// Client state retrieved number of messages for channels.
}
else {
// handler error condition
}
});
pubnub.messageCounts()
.channels(Arrays.asList("chats.room1", "chats.room2"))
.channelsTimetoken(Arrays.asList(15495750401727535L))
.async(result -> {
result.onSuccess(res -> {
for (Map.Entry<String, Long> entry : res.getChannels().entrySet()) {
entry.getKey(); // the channel name
entry.getValue(); // number of messages for that channel
}
}).onFailure(exception -> {
exception.printStackTrace();
});
});
pubnub.MessageCounts()
.Channels(new string[] { "chats.room1", "chats.room2" })
.ChannelsTimetoken(new long[] { 15495750401727535 })
.Execute(new PNMessageCountResultExt((result, status) => {
if (status != null && status.Error)
{
Console.WriteLine(status.ErrorData.Information);
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(result));
}
}));
envelope = pubnub.message_counts()\
.channel("chats.room1", "chats.room2") \
.channel_timetokens([15495750401727535])
.sync()
print(envelope.result.channels)