Manage server-side messages

Updated

Introduces how to use the Agora Chat SDK to retrieve messages from the server.

The Chat SDK stores historical messages on the chat server. When a chat user logs in from a different device, you can retrieve the historical messages from the server, so that the user can also browse these messages on the new device. Additionally, the Chat SDK supports adding tags to conversation, with a maximum of 20 tags allowed per conversation.

This page introduces how to use the Chat SDK to retrieve, delete, and tag messages and conversations.

Understand the tech

The Chat SDK uses ChatManager to retrieve historical messages from the server. The following are the core methods:

  • asyncFetchConversationsFromServer: Retrieves a list of conversations stored on the server.
  • asyncFetchHistoryMessages: Retrieves historical messages of a conversation from the server according to FetchMessageOption, the parameter configuration class for retrieving historical messages.
  • asyncPinConversation: Pins conversations.
  • asyncFetchPinnedConversationsFromServer: Retrieves pinned conversations.
  • asyncPinMessage: Pins a message in a conversation.
  • asyncUnPinMessage: Unpin a message in a conversation.
  • asyncGetPinnedMessagesFromServer: Get a list of pinned messages in a conversation.
  • removeMessagesFromServer: One-way deletion of historical messages on the server based on message time or message ID.
  • deleteConversationFromServer: Deletes conversations and their historical messages from the server.
  • asyncAddConversationMark: Tags a conversation.
  • asyncRemoveConversationMark: Removes a conversation tag.
  • asyncGetConversationsFromServerWithCursor: Queries conversations from the server by a conversation tag.

The Chat SDK uses IAgoraChatManager to retrieve historical messages from the server. The following are the core methods:

  • getConversationsFromServer: Retrieves a list of conversations stored on the server.
  • fetchMessagesFromServerBy: Retrieves historical messages of a conversation from the server according to AgoraChatFetchServerMessagesOption, the parameter configuration class for retrieving historical messages.
  • pinConversation: Pins a conversation.
  • getPinnedConversationsFromServerWithCursor: Retrieves a list of pinned conversations.
  • pinMessage: Pins a message in a conversation.
  • unpinMessage: Unpin a message in a conversation.
  • getPinnedMessagesFromServer: Get a list of pinned messages in a conversation.
  • removeMessagesFromServerWithTimeStamp/removeMessagesFromServerMessageIds: Deletes historical messages from the server unidirectionally.
  • deleteServerConversation: Deletes conversations and their historical messages from the server.
  • addConversationMark: Tags a conversation.
  • removeConversationMark: Removes a conversation tag.
  • getConversationsFromServer: Queries conversations from the server by a conversation tag.

Prerequisites

Before proceeding, ensure that you meet the following requirements:

  • You have integrated the Chat SDK, initialized the SDK and implemented the functionality of registering accounts and login. For details, see Chat SDK quickstart.
  • You understand the API call frequency limits as described in Limitations.

Implementation

This section shows how to implement retrieving conversations and messages.

Retrieve a list of conversations from the server

Call getConversationsFromServerWithCursor:pageSize:completion to retrieve conversations from the server with pagination. The SDK returns the conversation list in the reverse chronological order of when conversations are active (the timestamp of the last message in the conversation). In the conversation list, each conversation object contains the conversation ID, conversation type, whether the conversation is pinned, the pinned time (the value is 0 for an unpinned conversation), and the last message in the conversation. After the conversation list is retrieved from the server, the local conversation list will be updated accordingly. We recommend calling this method when the app is first installed, or when there is no conversation on the local device. Otherwise, you can call getAllConversations to retrieve conversations on the local device.

For each end user, the server stores 100 conversations by default. When this limit is exceeded, new conversations will start overwriting the old ones. If the entire message history in a conversation expires, the conversation becomes empty. When pulling the conversation list from the server, these empty conversations are not included by default. To include them, set EMOptions#loadEmptyConversations to YES when initializing the SDK. In this case, empty conversations will occupy the conversations pull quota, regardless of whether they are needed when pulling. To change this, contact support@agora.io.

//pageSize: The number of conversations that you expect to get on each page. The value range is [1,50].
[AgoraChatClient.sharedClient.chatManager getConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) {

}];

Retrieve historical messages of the specified conversation

After retrieving conversations, you can retrieve historical messages from the server.

You can set the search direction to retrieve messages in the chronological or reverse chronological order of when the server receives them, the message type, the time period, the message sender, as well as whether to save the retrieved message to the local database.

If you have integrated Chat SDK after June 8, 2023, you can retrieve historical messages even before joining the Chat Group. For earlier implementations, contact support@agora.io to enable this.

The Agora Chat server stores the full message history for a certain period of time depending on your subscribed Chat plan. After an end user logs back into Agora Chat, the servers automatically send offline messages to them, that is, messages transmitted when that end user was offline. Offline messages are a subset of the full message history stored on Agora Chat server. Sending only a subset of messages prevents distributing too many messages to a single device, which can overwhelm it and slow down the end user login. Agora Chat server stores and manages these offline messages for every end user in the following way:

  • 1
    private chat: Store 500 offline messages by default;
  • Chat Group: Store 200 offline messages by default;
  • Chatroom: Doesn't store offline messages. However, whenever an end user joins a chatroom, Agora Chat servers push the 10 latest messages/chatroom to them, by default. This number can be adjusted to 200 messages/chatroom without additional charges.

For users to receive more offline messages, use the client API or a webhook to sync with Agora Chat's server. End users can also store additional messages on their local database.

To ensure data reliability, we recommend retrieving less than 50 historical messages for each method call. To retrieve more than 50 historical messages, call this method multiple times. Once the messages are retrieved, the SDK automatically updates these messages in the local database.

Since SDK v1.4.0, for a single group conversation you can retrieve messages sent by specific members (rather than all members) by setting the fromIds list in AgoraChatFetchServerMessagesOption.

Refer to the following code sample:

AgoraChatFetchServerMessagesOption* option = [[AgoraChatFetchServerMessagesOption alloc] init];
    // Since SDK v1.4.0, for a group conversation you can retrieve messages sent by specific members.
    option.fromIds = @[@"user1", @"user2"];
    [AgoraChatClient.sharedClient.chatManager fetchMessagesFromServerBy:@"conversationId" conversationType:AgoraChatConversationTypeGroupChat cursor:@"" pageSize:20 option:option completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable aError) {

    }];

Search local messages sent by specific members

Since SDK v1.4.0, for a single conversation you can search the local database for messages that contain a keyword and are sent by specific members.

AgoraChatConversation *conversation = [AgoraChatClient.sharedClient.chatManager getConversationWithConvId:@"conversationId"];
if (conversation) {
    [conversation loadMessagesWithKeyword:nil timestamp:-1 count:20 fromUsers:@[@"user1", @"user2"] searchDirection:AgoraChatMessageSearchDirectionUp scope:AgoraChatMessageSearchScopeAll completion:^(NSArray<AgoraChatMessage *> * _Nullable aMessages, AgoraChatError * _Nullable aError) {
        if (aError == nil) {
            // Loaded successfully.
        }
    }];
}

Search local conversations by keyword

Since SDK v1.4.0, you can search across all local conversations for messages that contain a keyword. The SDK returns a dictionary of conversation IDs to the lists of matching message IDs. Each message ID list is ordered by message timestamp, in ascending or descending order according to the aDirection parameter.

[AgoraChatClient.sharedClient.chatManager loadConversationMessagesWithKeyword:@"keyword" timestamp:-1 fromUser:@"" searchDirection:AgoraChatMessageSearchDirectionUp scope:AgoraChatMessageSearchScopeAll completion:^(NSDictionary<NSString *,NSArray<NSString *> *> * _Nullable aConversationMessages, AgoraChatError * _Nullable aError) {
    if (aError == nil) {
        // aConversationMessages contains the matching conversation IDs and message IDs.
    }
}];

Retrieve local messages by message ID

Since SDK v1.4.0, you can pass one or more message IDs to retrieve messages from a single local conversation. You can pass a maximum of 20 message IDs at a time.

// You can pass a maximum of 20 message IDs at a time.
[AgoraChatClient.sharedClient.chatManager getMessages:@[@"messageId1", @"messageId2"] withConversationId:@"conversationId" completion:^(NSArray<AgoraChatMessage *> * _Nullable aMessages, AgoraChatError * _Nullable aError) {
    if (aError == nil) {
        // aMessages contains the retrieved messages.
    }
}];

Pin a conversation

To keep track of an important conversation, you can pin it to the top of your conversation list. You can pin up to 50 conversations. The pinned state is stored on the server. In a multi-device login use-case, if you pin or unpin a conversation, other login devices will receive the CONVERSATION_PINNED or CONVERSATION_UNPINNED events.

Refer to the following code example to pin a conversation:

[AgoraChatClient.sharedClient.chatManager pinConversation:@"conversationId" isPinned:YES completionBlock:^(AgoraChatError * _Nullable error) {

}];

Retrieve the pinned conversations from the server with pagination

End users can pin up to 50 conversations. After you call this API, the SDK returns the pinned conversations in the reverse chronological order of when they are pinned.

Agora Chat servers store a list of conversations that remain active in the past 7 days, regardless of Agora Chat package subscription. A conversation is considered active if it is pinned or there are new messages in a conversation.

Refer to the following code example to get a list of pinned conversations from the server with pagination:

// pageSize: Number of sessions returned per page. The value range is [1,50].
// cursor: The starting position of the query. If `nil` or `@""` is passed in, the SDK will start querying from the latest pinned session.
[AgoraChatClient.sharedClient.chatManager getPinnedConversationsFromServerWithCursor:@"" pageSize:20 completion:^(AgoraChatCursorResult * _Nullable result, AgoraChatError * _Nullable error) {

}];

Pin a message

You can call ChatManager#pinMessage to pin a message to the top of a one-to-one chat, chat group, or chat room. When the pinned status of a message changes, other members in the group or chat room conversation will receive the ChatManagerDelegate#onMessagePinChanged event. In the case of multi-device login, the updated top status will be synchronized to other logged-in devices, and other devices will receive the ChatManagerDelegate#onMessagePinChanged event, respectively.

In group and chat room conversations, multiple users can pin the same message to the top. The latest pinned message will overwrite the earlier information. That is, the MessagePinInfo user ID and pin time will correspond to the latest pinned message.

If the message is stored locally but deleted on the server due to expiration, the message will fail to be pinned to the top.

For a single conversation, 20 messages can be pinned to the top by default.

ChatClient.shared().chatManager?.pinMessage("messageId", completion: { message, err in
    if err == nil {
        // Pinned successfully
    }
})

Delete historical messages from the server unidirectionally

Call removeMessagesFromServerWithTimeStamp or removeMessagesFromServerMessageIds to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

Other devices logged in to the account will receive the MultiDevicesDelegate callback multiDevicesMessageBeRemoved, and the deleted messages will be automatically removed from the device locally.

// Delete messages by timestamp
AgoraChatConversation* conversation = [AgoraChatClient.sharedClient.chatManager getConversationWithConvId:@"conversationId"];
    [conversation removeMessagesFromServerWithTimeStamp:timeToRemove completion:^(AgoraChatError * _Nullable aError) {

    }];
// Delete messages by message ID
 [conversation removeMessagesFromServerMessageIds:@[@"msgId1",@"msgId2"] completion:^(AgoraChatError * _Nullable aError) {

    }];

Call deleteServerConversation to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on the local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

[AgoraChatClient.sharedClient.chatManager deleteServerConversation:@"conversationId1" conversationType:AgoraChatConversationTypeChat isDeleteServerMessages:YES completion:^(NSString *aConversationId, AgoraChatError *aError) {

    }];

Next steps

After implementing retrieving messages, you can refer to the following documents to add more messaging functionalities to your app: