# Message receipts (/en/realtime-media/im/build/build-core-messaging/messages/message-receipts)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="web" platforms="[&#x22;android&#x22;,&#x22;ios&#x22;,&#x22;web&#x22;,&#x22;flutter&#x22;,&#x22;react-native&#x22;,&#x22;windows&#x22;,&#x22;unity&#x22;]" showTabs="true">
  <_PlatformPanel platform="android">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech]

    The Chat SDK uses `ChatManager` to provide message receipt. The following are the core methods:

    * `ChatOptions.setRequireAck`: Enables message read receipt.
    * `ChatOptions.setRequireDeliveryAck`: Enables message delivery receipt.
    * `ackConversationRead`: Sends a conversation read receipt.
    * `ackMessageRead`: Sends a message read receipt.
    * `ackGroupMessageRead`: Sends a message read receipt for group chat.

    The logic for implementing these receipts are as follows:

    * Message delivery receipts

      1. The message sender enables delivery receipts by setting `ChatOptions.setRequireDeliveryAck` as `true`.
      2. After the recipient receives the message, the SDK automatically sends a delivery receipt to the sender.
      3. The sender receives the delivery receipt by listening for `onMessageDelivered`.

    * Conversation and message read receipts

      1. The message sender enables read receipt by setting `ChatOptions.setRequireAck` as `true`.
      2. After reading the message, the recipient calls `ackConversationRead` or `ackMessageRead` to send a conversation or message read receipt.
      3. The sender receives the conversation or message receipt by listening for `onConversationRead` or `onMessageRead`.

    ## Prerequisites [#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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts]

    To send a message delivery receipt, take the following steps:

    1. The message sender sets `setRequireDeliveryAck` in `ChatOptions` as `true` before sending the message:

       ```java
       ChatOptions chatOptions = new ChatOptions();
       chatOptions.setRequireDeliveryAck(true);
       ...
       ChatClient.getInstance().init(mContext, chatOptions);
       ```

    2. Once the recipient receives the message, the SDK triggers `onMessageDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient.

       ```java
       // Add a message listener to listen for the receipt message.
       MessageListener msgListener = new MessageListener() {
           // Occurs when the message is received.
           @Override
           public void onMessageReceived(List messages) {
           }
           // Occurs when the message delivery receipt is received
           @Override
           public void onMessageDelivered(List message) {
           }
       };
       // Register a message listener.
       ChatClient.getInstance().chatManager().addMessageListener(msgListener);
       // Remove the message listener when it is not used.
       ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    * Conversation read receipts

      Follow the steps to implement conversation read receipts in one-to-one chats.

      1. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `ackConversationRead` to send a conversation read receipt.

         ```java
         // The message receiver calls ackConversationRead to send the conversation read receipt.
         // This is an asynchronous method.
         try {
             ChatClient.getInstance().chatManager().ackConversationRead(conversationId);
         } catch (ChatException e) {
             e.printStackTrace();
         }
         ```

      2. The message sender listens for message events and receives the conversation read receipt in `onConversationRead`.

         ```java
         // The message sender calls addConversationListener to listen for conversation events.
         ChatClient.getInstance().chatManager().addConversationListener(new ConversationListener() {
                     ...
                     @Override
                     // Occurs when the all the messages in the conversation is read.
                     public void onConversationRead(String from, String to) {
                         // Add follow-up logics such as poping up a notification.
                     }
                 });
         ```

      <CalloutContainer type="info">
        <CalloutDescription>
          In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation as 0, and all the other devices receive `onConversationRead`.
        </CalloutDescription>
      </CalloutContainer>

    * Message read receipts

      To implement the message read receipt, take the following steps:

      1. Send a conversation read receipt when the recipient enters the conversation.

         ```java
         // The message receiver calls ackConversationRead to send the conversation read receipt.
         try {
             ChatClient.getInstance().chatManager().ackConversationRead(conversationId);
         }catch (ChatException e) {
             e.printStackTrace();
         }
         ```

      2. When a new message arrives, send the message read receipt and add proper handling logics for the different message types.

         ```java
         ChatClient.getInstance().chatManager().addMessageListener(new MessageListener() {
             ......

             @Override
             // Occurs when the specified message is received.
             public void onMessageReceived(List messages) {
                 ......
                 // Send the message read receipt.
                 sendReadAck(message);
                 ......
             }
             ......
         });
         // Send the message read receipt.
         public void sendReadAck(ChatMessage message) {
             // For messages in one-to-one chat
             if(message.direct() == ChatMessage.Direct.RECEIVE
                     undefined message.getChatType() == ChatMessage.ChatType.Chat) {
                 ChatMessage.Type type = message.getType();
                 // For voice, video, and file messages, you need to send the receipt after clicking the files.
                 if(type == ChatMessage.Type.VIDEO || type == ChatMessage.Type.VOICE || type == ChatMessage.Type.FILE) {
                     return;
                 }
                 try {
                     // Call ackMessageRead to send the message read receipt.
                     ChatClient.getInstance().chatManager().ackMessageRead(message.getFrom(), message.getMsgId());
                 } catch (ChatException e) {
                     e.printStackTrace();
                 }
             }
         }
         ```

      3. The message sender listens for the message receipt:

         ```java
         // The message sender calls addMessageListener to listen for message events.
         ChatClient.getInstance().chatManager().addMessageListener(new MessageListener() {
             ......
             @Override
             // Occurs when the specified message is read.
             public void onMessageRead(List messages) {
                 // Add follow-up logics such as poping up a notification.
             }
             ......
         });
         ```

    #### Chat groups [#chat-groups]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default           | Description                                                                                                                                                                                                                                                                              |
    | :------------------------------------------------------------------------------- | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled          | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                                                                  |
    | Permission                                                                       | All group members | By default, all group members can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission only to the group owner and administrators.                                                                         |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days            | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                                                                           |
    | Chat group size                                                                  | 200 members       | This feature is available only to groups with up to 200 members. If the upper limit is exceeded, no read receipts are returned for the message sent within the group. To increase the upper limit of group member count, you can contact [support@agora.io](mailto\:support@agora.io).   |
    | View the number of read receipts returned for a group message                    | Message sender    | By default, only the message sender can view the number of read receipts returned for a group message (or the number of group members that have returned the read receipts). To allow all group members to view the count, you can contact [support@agora.io](mailto\:support@agora.io). |

    Follow the steps to implement read receipts for a chat group message:

    1. When sending a message, a group member can set whether to require a message read receipt.

       ```java
       // Set setIsNeedGroupAck as true when sending the group message
       ChatMessage message = ChatMessage.createTextSendMessage(content, to);
       message.setIsNeedGroupAck(true);
       ```

    2. After the group member reads the chat group message, call `ackGroupMessageRead` from the group member's client to send a message read receipt.

       ```java
       // Send the group message read receipt.
       public void sendAckMessage(ChatMessage message) {
               if (!validateMessage(message)) {
                   return;
               }

               if (message.isAcked()) {
                   return;
               }

               // May a user login from multiple devices, so do not need to send the ack msg.
               if (ChatClient.getInstance().getCurrentUser().equalsIgnoreCase(message.getFrom())) {
                   return;
               }

               try {
                   if (message.isNeedGroupAck() && !message.isUnread()) {
                       String to = message.conversationId(); // do not use getFrom() here
                       String msgId = message.getMsgId();
                       ChatClient.getInstance().chatManager().ackGroupMessageRead(to, msgId, ((TextMessageBody)message.getBody()).getMessage());
                       message.setUnread(false);
                       EMLog.i(TAG, "Send the group ack cmd-type message.");
                   }
               } catch (Exception e) {
                   EMLog.d(TAG, e.getMessage());
               }
           }
       ```

    3. The message sender listens for the message read receipt.

       ```java
       // Occurs when the group message is read.
       void onGroupMessageRead(List groupReadAcks) {
           // Add follow-up notifications
       }
       ```

    4. The message sender can get the detailed information of the read receipt using `asyncFetchGroupReadAcks`.

       ```java
       // msgId: The message ID.
       // pageSize: The page size. The value range is [1,50].
       // startAckId: The starting receipt ID for query. Set it as null for the first call of the method and the SDK retrieves from the latest receipt.
       * @return The message receipt list and a cursor.
       */
       ChatClient.getInstance().chatManager().asyncFetchGroupReadAcks(msgId, pageSize, startAckId, new ValueCallBack>() {
          @Override
          public void onSuccess(CursorResult value) {// Succeeded in getting the details of the read receipt.
          }
          @Override
          public void onError(int error, String errorMsg) {
           // Failed to get the details of the read receipt.
          }
       });
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="ios">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-1]

    The Chat SDK uses `IAgoraChatManager` to provide message receipt. The following are the core methods:

    * `AgoraChatOptions.enableRequireReadAck`: Enables message read receipt.
    * `AgoraChatOptions.enableDeliveryAck`: Enables message delivery receipt.
    * `ackConversationRead`: Sends a conversation read receipt.
    * `sendMessageReadAck`: Sends a message read receipt.
    * `sendGroupMessageReadAck`: Sends a message read receipt for group chat.

    The logic for implementing these receipts are as follows:

    * Message delivery receipts

      1. The message sender enables delivery receipts by setting `AgoraChatOptions.enableDeliveryAck` as `YES`.
      2. After the recipient receives the message, the SDK automatically sends a delivery receipt to the sender.
      3. The sender receives the delivery receipt by listening for `messageDidDeliver`.

    * Conversation and message read receipts

      1. The message sender enables read receipt by setting `AgoraChatOptions.enableRequireReadAck` as `YES`.
      2. After reading the message, the recipient calls `ackConversationRead` or `sendMesageReadAck` to send a conversation or message read receipt.
      3. The sender receives the conversation or message receipt by listening for `onConversationRead` or `messageDidRead`.

    ## Prerequisites [#prerequisites-1]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-1]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-1]

    To send a message delivery receipt, take the following steps:

    1. The message sender sets `enableDeliveryAck` in `AgoraChatOptions` as `YES` before sending the message:

       ```objc
       options.enableDeliveryAck = YES;
       ```

    2. Once the recipient receives the message, the SDK triggers `messageDidDeliver` on the message sender's client, notifying the message sender that the message has been delivered to the recipient.

       ```objc
       - (void)messagesDidDeliver:(NSArray *)aMessages
       {

       }

       [[AgoraChatClient sharedClient].chatManager removeDelegate:self];
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-1]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats-1]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    * Conversation read receipts

    Follow the steps to implement conversation read receipts in one-to-one chats.

    1. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `ackConversationRead` to send a conversation read receipt.

       ```objc
       [[AgoraChatClient sharedClient].chatManager ackConversationRead:conversationId completion:nil];
       ```

    2. The message sender listens for message events and receives the conversation read receipt in `onConversationRead`.

       ```objc
       - (void)onConversationRead:(NSString *)from to:(NSString *)to
       {
           // Add handling logics, for example, for refreshing the UI
       }
       ```

       <CalloutContainer type="info">
         <CalloutDescription>
           In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation as 0, and all the other devices receive `onConversationRead`.
         </CalloutDescription>
       </CalloutContainer>

    * Message read receipts

    To implement the message read receipt, take the following steps:

    1. Send a conversation read receipt when the recipient enters the conversation.

       ```objc
       [[AgoraChatClient sharedClient].chatManager sendMessageReadAck:messageId toUser:conversationId completion:nil];
       ```

    2. When a new message arrives, send the message read receipt and add proper handling logics for the different message types.

       ```objc
       // Occurs when the message is received.
       - (void)messagesDidReceive:(NSArray *)aMessages
       {
           for (AgoraChatMessage *message in aMessages) {
               // Sends a message read receipt
               [self sendReadAckForMessage:message];
           }
       }

       - (void)sendReadAckForMessage:(AgoraChatMessage *)aMessage
       {
           // The received message
           if (aMessage.direction == AgoraChatMessageDirectionSend || aMessage.isReadAcked || aMessage.chatType != AgoraChatTypeChat)
               return;

           MessageBody *body = aMessage.body;
           // For audio, video, and file messages, send them after the user clicks the file.
           if (body.type == MessageBodyTypeFile || body.type == MessageBodyTypeVoice || body.type == MessageBodyTypeImage)
               return;

           [[AgoraChatClient sharedClient].chatManager sendMessageReadAck:aMessage.messageId toUser:aMessage.conversationId completion:nil];
       }
       ```

    3. The message sender listens for the message receipt:

       ```objc
       // Occurs when the message read receipt is received
       - (void)messagesDidRead:(NSArray *)aMessages
       {
           for (AgoraChatMessage *message in aMessages) {
               // Adds handling logics
           }
       }
       ```

    #### Chat groups [#chat-groups-1]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default                        | Description                                                                                                                                                                                                                                |
    | :------------------------------------------------------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled                       | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                    |
    | Permission                                                                       | Group owner and administrators | By default, only the group owner and administrators can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission to regular group members.                       |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days                         | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                             |
    | Chat group size                                                                  | 500 members                    | This feature is available only to groups with up to 500 members. In other words, each message in a group can have up to 500 read receipts. If the upper limit is exceeded, the latest read receipt record will overwrite the earliest one. |
    | Maximum number of group messages that can have read receipts per day             | 500                            | A group can have up to 500 messages each day for which read receipts can be returned.                                                                                                                                                      |

    Follow the steps to implement read receipts for a chat group message:

    1. When sending a message, a group member can set whether to require a message read receipt.

       ```objc
       AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:to from:from to:to body:aBody ext:aExt];
       message.isNeedGroupAck = YES;
       ```

    2. After the group member reads the chat group message, call `sendGroupMessageReadAck` from the group member's client to send a message read receipt:

       ```objc
       - (void)sendGroupMessageReadAck:(AgoraChatMessage *)msg
       {
           if (msg.isNeedGroupAck && !msg.isReadAcked) {
               [[AgoraChatClient sharedClient].chatManager sendGroupMessageReadAck:msg.messageId toGroup:msg.conversationId content:@"123" completion:^(AgoraChatError *error) {
                   if (error) {

                   }
               }];
           }
       }
       ```

    3. The message sender listens for the message read receipt.

       ```objc
       // Occurs when the group message is received.
       - (void)groupMessageDidRead:(AgoraChatMessage *)aMessage groupAcks:(NSArray *)aGroupAcks
       {
           for (AgoraChatGroupMessageAck *messageAck in aGroupAcks) {
               //receive group message read ack
           }
       }
       ```

    4. The message sender can get the detailed information of the read receipt using `asyncFetchGroupMessageAcksFromServer`.

       ```objc
       // messageId: The message ID.
       // pageSize: The page size. The value range is [1,50].
       // startGroupAckId: The starting receipt ID for query. Set it as nil or "" for the first call of the method and the SDK retrieves from the latest receipt.
       [[AgoraChatClient sharedClient].chatManager asyncFetchGroupMessageAcksFromServer:messageId groupId:groupId startGroupAckId:nil pageSize:pageSize completion:^(AgoraChatCursorResult *aResult, AgoraChatError *error, int totalCount) {
           // Add subsequent logics, for example, refreshing the UI
       }];
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="web">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-2]

    The message delivery receipts and read receipts are implemented as follows:

    * Message delivery receipt for one-to-one chats

      1. The message sender enables delivery receipts by setting `delivery` as `true` when creating the `connection` object during SDK initialization.
      2. A user sends a message.
      3. After the recipient receives the message, the SDK automatically sends a delivery receipt to the sender.
      4. The sender receives the delivery receipt by listening for `onDeliveredMessage`.

    * Conversation and message read receipts for one-to-one chats

      1. A user sends a message.
      2. After reading the message, the recipient calls `send` to send a conversation or message read receipt.
      3. The sender receives the conversation or message receipt by listening for `onChannelMessage` or `onReadMessage`.

    * Message read receipt for group chats

      1. A group member sends a message with `allowGroupAck` set to `true` to request message read receipts.
      2. After reading the message, the recipient calls `send` to send a read receipt.
      3. The sender receives the message read receipt by listening for `onReadMessage` when online or `onStatisticsMessage` when offline.
      4. The sender can know which group members have read the message by calling `getGroupMsgReadUser`.

    ## Prerequisites [#prerequisites-2]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-2]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-2]

    To send a message delivery receipt, take the following steps:

    1. The message sender sets `delivery` in `options` as `true` when initializing the `connection` object.

       ```javascript
       const chatClient = new AgoraChat.connection({
         appKey: "your appKey",
         delivery: true,
       });
       ```

    2. Once the recipient receives the message, the SDK triggers `onDeliveredMessage` on the message sender's client, notifying that the message has been delivered to the recipient.
       ```javascript
       chatClient.addEventHandler("handlerId", {
         onReceivedMessage: function (message) {}, // Received a receipt for message delivery to the server.
         onDeliveredMessage: function (message) {}, // Received a receipt for message delivery to the client.
       });
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-2]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chat [#one-to-one-chat]

    The one-to-one chats support both conversation read receipts and message read receipts. We recommend you use both types of read receipts together to reduce the number of message read receipts:

    * If several messages are received when the chat page is not opened yet, send a conversation read receipt when the chat page is opened.
    * If a message is received on an open chat page, send a message read receipt.

    ##### Conversation read receipts [#conversation-read-receipts]

    1. The message recipient sends a conversation read receipt.

       The message recipient opens the conversation page to check whether there are unread messages. If yes, call `send` to send a conversation read receipt.

       ```javascript
       const options = {
         chatType: "singleChat", // The chat type: singleChat for one-to-one.
         type: "channel", // The type of read receipt: channel indicates the conversation read receipt.
         to: "userId", // The user ID of the message recipient.
       };
       const msg = AgoraChat.message.create(options);
       chatClient.send(msg);
       ```

    2. The message sender receives the conversation read receipt in the `onChannelMessage` callback.

       ```javascript
       chatClient.addEventHandler("handlerId", {
         onChannelMessage: (message) => {},
       });
       ```

    ##### Message read receipts [#message-read-receipts]

    For one-to-one chats, message read receipts are stored as long as messages on the Chat server. Specifically, message read receipts can be sent whenever the messages are available on the Chat server. The message storage period on the Chat server depends on your product plan. For details, see the [pricing plan details](../../../reference/pricing-plan-details#message).

    Refer to the following steps to implement message read receipt in one-to-one chats:

    1. The message recipient sends a message read receipt.

       * If there are several unread messages in the conversation, to minimize the number of sent message read receipts, we recommend that a conversation read receipt be sent when the message recipient enters the conversation.

         ```javascript
         const options = {
           chatType: "singleChat", // The chat type: singleChat for one-to-one chat.
           type: "channel", // The type of read receipt: channel indicates the conversation read receipt.
           to: "userId", // The user ID of the message receipt.
         };
         const msg = AgoraChat.message.create(options);
         chatClient.send(msg);
         ```

       * If there is only one unread message in the conversation, after reading it, call `send` from the recipient's client to send the message read receipt.

         ```javascript
         const options = {
           type: "read", // The message read receipt.
           chatType: "singleChat", // The chat type: singleChat for one-to-one chat.
           to: "userId", // The user ID of the message receipt.
           id: "id", // The ID of the message that requires the read receipt.
         };
         const msg = AgoraChat.message.create(options);
         chatClient.send(msg);
         ```

    2. The message sender listens for `onReadMessage` to receive the message read receipt.

       ```javascript
       chatClient.addEventHandler("handlerId", {
         onReadMessage: (message) => {},
       });
       ```

    #### Group chat [#group-chat]

    <CalloutContainer type="success">
      <CalloutDescription>
        For group chats, the conversation read receipt is only used to clear the
        unread message count of the group chat on the server. The message sender
        will not receive the conversation read receipt via the `onChannelMessage`
        callback.
      </CalloutDescription>
    </CalloutContainer>

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    | Feature Restriction                                                              | Default           | Description                                                                                                                                                                                                                                                                              | Error                                                                                                                                                                                                      |
    | :------------------------------------------------------------------------------- | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled          | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                                                                  | The error 503 "group ack not open" is returned if you fail to enable this feature before using it.                                                                                                         |
    | Permission                                                                       | All group members | By default, all group members can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission only to the group owner and administrators.                                                                         | If you only allow the group owner and administrators to send read receipts, the error "group ack msg permission denied" is returned if regular group members request read receipts when sending a message. |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days            | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                                                                           | The error "group ack msg not found" is returned if read receipts are sent three days after the message is sent.                                                                                            |
    | Chat group size                                                                  | 200 members       | This feature is available only to groups with up to 200 members. If the upper limit is exceeded, no read receipts are returned for the message sent within the group. To increase the upper limit of group member count, you can contact [support@agora.io](mailto\:support@agora.io).   |                                                                                                                                                                                                            |
    | View the number of read receipts returned for a group message                    | Message sender    | By default, only the message sender can view the number of read receipts returned for a group message (or the number of group members that have returned the read receipts). To allow all group members to view the count, you can contact [support@agora.io](mailto\:support@agora.io). |                                                                                                                                                                                                            |

    Follow the steps to implement read receipts for a chat group message:

    1. When sending a message, a group member can set whether to require a message read receipt by setting `allowGroupAck` to `true`.

       ```javascript
       sendGroupReadMsg = () => {
          const options = {
              type: 'txt',            // Message type.
              chatType: 'groupChat',  // Conversation type: groupChat for group chat.
              to: 'groupId',          // The message recipient: group ID.
              msg: 'message content'  // Message content.
              msgConfig: { allowGroupAck: true } // Setting that this message requires a read receipt.
          }

         const msg = AgoraChat.message.create(options);
         chatClient.send(msg).then((res) => {
             console.log('send message success');
         }).catch((e) => {
             console.log("send message error");
         })
       }
       ```

    2. After reading the group message, the recipient calls `send` to send the message read receipt.

       ```javascript
       sendReadMsg = () => {
         const options = {
           type: "read", // Whether the message has been read.
           chatType: "groupChat", // Conversation type: groupChat means group chat.
           id: "msgId", // The message ID for which the read receipt is sent.
           to: "groupId", // Group ID.
           ackContent: JSON.stringify({}), // The content of the message read receipt.
         };
         const msg = AgoraChat.message.create(options);
         chatClient.send(msg);
       };
       ```

    3. The message sender receives the message read receipt by listening for either of the following callbacks:

       * `onReadMessage`, when the message sender is online.
       * `onStatisticsMessage`, when the message sender is offline.

         ```javascript
         // You can listen in onReadMessage when online.
         chatClient.addEventHandler("handlerId", {
           onReadMessage: (message) => {
             let { mid } = message;
             let msg = {
               id: mid,
             };
             if (message.groupReadCount) {
               // The message has been read.
               msg.groupReadCount = message.groupReadCount[message.mid];
             }
           },
           // You can listen for onStatisticMessage upon login when the read receipt is received when you are offline.
           onStatisticMessage: (message) => {
             let statisticMsg = message.location && JSON.parse(message.location);
             let groupAck = statisticMsg.group_ack || [];
           },
         });
         ```

    4. After receiving the read receipt, the message sender can retrieve the detailed information of the group members that have read the message.

       ```javascript
       chatClient
         .getGroupMsgReadUser({
           msgId: "messageId", // Message ID.
           groupId: "groupId", // Group ID.
         })
         .then((res) => {
           console.log(res);
         });
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="flutter">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-3]

    The Chat SDK uses `ChatManager` to provide message receipt, which includes delivery receipts and read receipts. The following are the core methods:

    * `ChatOptions.requireDeliveryAck`: Enable message delivery receipts.
    * `ChatOptions.requireAck`: Enable conversation and message read receipts.
    * `ChatManager.sendConversationReadAck`: Send a conversation read receipt.
    * `ChatManager.sendMessageReadAck`: Send a message read receipt.
    * `ChatManager.sendGroupMessageReadAck`: Send a group message read receipt.

    The logic for implementing these receipts are as follows:

    * Message delivery receipts

      1. The message sender enables delivery receipts by setting `ChatOptions.requireDeliveryAck` as `true`.
      2. After the recipient receives the message, the SDK automatically sends a delivery receipt to the sender.
      3. The sender receives the delivery receipt by listening for `onMessageDelivered`.

    * Conversation and message read receipts

      1. The message sender enables read receipt by setting `ChatOptions.requireAck` as `true`.
      2. After reading the message, the recipient calls `sendConversationReadAck` or `sendMessageReadAck` to send a conversation or message read receipt.
      3. The sender receives the conversation or message receipt by listening for `onConversationRead` or `onMessagesRead`.

    ## Prerequisites [#prerequisites-3]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-3]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-3]

    To send a message delivery receipt, take the following steps:

    1. When initializing the SDK, set `requireDeliveryAck` in `ChatOptions` as `true` on the sender's client.

       ```dart
       // The App Key
       String appKey = "appKey";
       // Enables message delivery receipt
       bool requireDeliveryAck = true;
       ChatOptions options = ChatOptions(
       appKey: appKey,
       requireDeliveryAck: requireDeliveryAck,
       );
       await ChatClient.getInstance.init(options);
       ```

    2. Once the recipient receives the message, the SDK triggers `onMessagesDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient. Listen for the `onMessagesDelivered` callback on the sender's client:

       ```dart
       ChatClient.getInstance.chatManager.addEventHandler(
         "UNIQUE_HANDLER_ID",
         ChatEventHandler(
           onMessagesDelivered: (messages) {},
         ),
       );
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-3]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats-2]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    ##### Conversation read receipts [#conversation-read-receipts-1]

    Follow the steps to implement conversation read receipts in one-to-one chats.

    1. When initializing the SDK, set `requireAck` in `ChatOptions` as `true`.

       ```dart
       ChatOptions options = ChatOptions(
       appKey: "",
       requireAck: true,
       );
       ChatClient.getInstance.init(options);
       ```

    2. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `sendConversationReadAck` to send a conversation read receipt.

       ```dart
       String convId = "convId";
       try {
       await ChatClient.getInstance.chatManager.sendConversationReadAck(convId);
       } on ChatError catch (e) {
       // Sending conversation read receipts fails. See e.code for the error code and e.description for the error description.
       }
       ```

    3. The message sender listens for message events and receives the conversation read receipt in `onConversationRead`.

       ```dart
       ChatClient.getInstance.chatManager.addEventHandler(
         "UNIQUE_HANDLER_ID",
         ChatEventHandler(
           onConversationRead: (from, to) {},
         ),
       );
       ```

    <CalloutContainer type="info">
      <CalloutDescription>
        In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation as 0, and all the other devices receive `onConversationRead`.
      </CalloutDescription>
    </CalloutContainer>

    ##### Message read receipts [#message-read-receipts-1]

    To implement the message read receipt in one-to-one chats, take the following steps:

    1. When initializing the SDK, set `requireAck` in `ChatOptions` as `true`.

       ```dart
       ChatOptions options = ChatOptions(
       appKey: "",
       requireAck: true,
       );
       ChatClient.getInstance.init(options);
       ```

    2. The message sender listens for the message receipt in `onMessagesRead`:

       ```dart
       ChatClient.getInstance.chatManager.addEventHandler(
         "UNIQUE_HANDLER_ID",
         ChatEventHandler(
           onMessagesRead: (messages) {},
         ),
       );
       ```

    3. When the message arrives, the recipient reads the message and calls `sendMessageReadAck` to notify the sender that the message is read. The SDK will trigger `onMessagesRead` on the sender's client.

       ```dart
       try {
       ChatClient.getInstance.chatManager.sendMessageReadAck(msg);
       } on ChatError catch (e) {
       // Fails to send the message. See e.code for the error code, and e.description for the error description.
       }
       ```

    #### Chat groups [#chat-groups-2]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default                        | Description                                                                                                                                                                                                                                |
    | :------------------------------------------------------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled                       | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                    |
    | Permission                                                                       | Group owner and administrators | By default, only the group owner and administrators can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission to regular group members.                       |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days                         | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                             |
    | Chat group size                                                                  | 500 members                    | This feature is available only to groups with up to 500 members. In other words, each message in a group can have up to 500 read receipts. If the upper limit is exceeded, the latest read receipt record will overwrite the earliest one. |
    | Maximum number of group messages that can have read receipts per day             | 500                            | A group can have up to 500 messages each day for which read receipts can be returned.                                                                                                                                                      |

    Follow the steps to implement read receipts for a chat group message:

    1. To receive the chat group message read receipts, the sender listens for the `onGroupMessageRead` callback.

       ```dart
       ChatClient.getInstance.chatManager.addEventHandler(
         "UNIQUE_HANDLER_ID",
         ChatEventHandler(
           onGroupMessageRead: (messages) {},
         ),
       );
       ```

    2. The sender sends a chat group message. Ensure that you set `needGroupAck` as `true`.

       ```dart
       // Sets the chat type as group chat
       msg.chatType = ChatType.GroupChat;
       // Whether to require a group message read receipt
       msg.needGroupAck = true;
       try {
       await ChatClient.getInstance.chatManager.sendMessage(msg);
       } on ChatError catch (e) {
           // Fails to send the message. See e.code for the error code, and e.description for the error description.
       }
       ```

    3. The chat group member reads the message and call `sendGroupMessageReadAck` to send a chat group message receipt. The SDK will trigger `onGroupMessageRead` on the sender's client.

       ```dart
       try {
       ChatClient.getInstance.chatManager.sendGroupMessageReadAck(msgId, groupId);
       } on ChatError catch (e) {
       // Fails to send the group message read receipt. See e.code for the error code, and e.description for the error description.
       }
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="react-native">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="react-native" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-4]

    The Chat SDK uses `IChatManager` to provide message receipt, which includes delivery receipts and read receipts. The following are the core methods:

    * `ChatOptions.requireDeliveryAck`: Enable message delivery receipts.
    * `ChatOptions.requireAck`: Enable conversation and message read receipts.
    * `ChatManager.sendConversationReadAck`: Send a conversation read receipt.
    * `ChatManager.sendMessageReadAck`: Send a message read receipt.
    * `ChatManager.sendGroupMessageReadAck`: Send a group message read receipt.

    The logic for implementing these receipts are as follows:

    * Message delivery receipts

      1. The message sender enables delivery receipts by setting `ChatOptions.requireDeliveryAck` as `true`.
      2. After the recipient receives the message, the SDK automatically sends a delivery receipt to the sender.
      3. The sender receives the delivery receipt by listening for `onMessageDelivered`.

    * Conversation and message read receipts

      1. The message sender enables read receipt by setting `ChatOptions.requireAck` as `true`.
      2. After reading the message, the recipient calls `sendConversationReadAck` or `sendMessageReadAck` to send a conversation or message read receipt.
      3. The sender receives the conversation or message receipt by listening for `onConversationRead` or `onMessageRead`.

    ## Prerequisites [#prerequisites-4]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-4]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-4]

    To send a message delivery receipt, take the following steps:

    1. When initializing the SDK, set `requireDeliveryAck` in `ChatOptions` as `true` on the sender's client.

       ```typescript
       // Set the SDK app key.
       const appKey = "appKey";
       // Enable message delivery receipts.
       const requireDeliveryAck = true;
       ChatClient.getInstance()
       .init(
           new ChatOptions({
           appKey,
           requireDeliveryAck,
           })
       )
       .then(() => {
           console.log("init sdk success");
       })
       .catch((reason) => {
           console.log("init sdk fail.", reason);
       });
       ```

    2. Once the recipient receives the message, the SDK triggers `OnMessageDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient. Listen for the `onMessageDelivered` callback on the sender's client:

       ```typescript
       class ChatMessageEvent implements ChatMessageEventListener {
       onMessagesDelivered(messages: ChatMessage[]): void {
           console.log(`onMessagesDelivered: `, messages);
       }
       // ...
       }
       // Add a message listener
       const listener = new ChatMessageEvent();
       ChatClient.getInstance().chatManager.addMessageListener(listener);
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-4]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats-3]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    ##### Conversation read receipts [#conversation-read-receipts-2]

    Follow the steps to implement conversation read receipts in one-to-one chats.

    1. When initializing the SDK, set `requireAck` in `ChatOptions` as `true`.

       ```typescript
       // Set the SDK app key.
       const appKey = "appKey";
       // Enable the conversation and message read receipt.
       const requireAck = true;
       ChatClient.getInstance()
       .init(
           new ChatOptions({
           appKey,
           requireAck,
           requireDeliveryAck,
           })
       )
       .then(() => {
           console.log("init sdk success");
       })
       .catch((reason) => {
           console.log("init sdk fail.", reason);
       });
       ```

    2. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `sendConversationReadAck` to send a conversation read receipt.

       ```typescript
       // Get the conversation ID
       const convId = "convId";
       // Call sendConversationReadAck to send the receipt.
       ChatClient.getInstance()
       .chatManager.sendConversationReadAck(convId)
       .then(() => {
           console.log("send conversation read success");
       })
       .catch((reason) => {
           console.log("send conversation read fail.", reason);
       });
       ```

    3. The message sender listens for message events and receives the conversation read receipt in `onConversationRead`.

       ```typescript
       class ChatMessageEvent implements ChatMessageEventListener {
       onConversationRead(from: string, to?: string): void {
           // `from` indicates the message recipient that sends this receipt, and `to` indicates the message sender that receives this receipt.
           console.log(`onConversationRead: `, from, to);
       }
       // ...
       }
       // Add a chat message event.
       const listener = new ChatMessageEvent();
       ChatClient.getInstance().chatManager.addMessageListener(listener);
       ```

    <CalloutContainer type="info">
      <CalloutDescription>
        In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation as 0, and all the other devices receive `onConversationRead`.
      </CalloutDescription>
    </CalloutContainer>

    ##### Message read receipts [#message-read-receipts-2]

    To implement the message read receipt in one-to-one chats, take the following steps:

    1. When initializing the SDK, set `requireAck` in `ChatOptions` as `true`.

       ```typescript
       // Set the SDK app key.
       const appKey = "appKey";
       // Enable the conversation and message read receipt.
       const requireAck = true;
       ChatClient.getInstance()
       .init(
           new ChatOptions({
           appKey,
           requireAck,
           requireDeliveryAck,
           })
       )
       .then(() => {
           console.log("init sdk success");
       })
       .catch((reason) => {
           console.log("init sdk fail.", reason);
       });
       ```

    2. The message sender listens for the message receipt in `onMessageRead`:

       ```typescript
       class ChatMessageEvent implements ChatMessageEventListener {
       onMessagesRead(messages: ChatMessage[]): void {
           // Receive the onMessageRead callback
           console.log(`onMessagesRead: `, messages);
       }
       // ...
       }
       // Add a chat message event.
       const listener = new ChatMessageEvent();
       ChatClient.getInstance().chatManager.addMessageListener(listener);
       ```

    3. The sender sends a message. Ensure that you set `msg.hasReadAck` as `true`.

       ```typescript
       // Send a message.
       // Set hasReadAck as true to require a message read receipt.
       msg.hasReadAck = true;
       // Call sendMessage to send the message
       ChatClient.getInstance()
       .chatManager.sendMessage(msg)
       .then(() => {
           // Print a log if message sending succeeds.
           console.log("send message success.");
       })
       .catch((reason) => {
           // Print a log if message sends fails.
           console.log("send message fail.", reason);
       });
       ```

    4. When the message arrives, the recipient reads the message and call `sendMessageReadAck` to notify the send that the message is read. The SDK will trigger `onMessageRead` on the sender's client.

       ```typescript
       // The message that requires a read receipt.
       const msg;
       // Call sendMessageReadAck to send a message read receipt.
       ChatClient.getInstance()
       .chatManager.sendMessageReadAck(msg)
       .then(() => {
           console.log("send message read success");
       })
       .catch((reason) => {
           console.log("send message read fail.", reason);
       });
       ```

    #### Chat groups [#chat-groups-3]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default                        | Description                                                                                                                                                                                                                                |
    | :------------------------------------------------------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled                       | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                    |
    | Permission                                                                       | Group owner and administrators | By default, only the group owner and administrators can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission to regular group members.                       |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days                         | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                             |
    | Chat group size                                                                  | 500 members                    | This feature is available only to groups with up to 500 members. In other words, each message in a group can have up to 500 read receipts. If the upper limit is exceeded, the latest read receipt record will overwrite the earliest one. |
    | Maximum number of group messages that can have read receipts per day             | 500                            | A group can have up to 500 messages each day for which read receipts can be returned.                                                                                                                                                      |

    Follow the steps to implement read receipts for a chat group message:

    1. To receive the chat group message read receipts, the sender listens for the `onGroupMessageRead` callback.

       ```typescript
       class ChatMessageEvent implements ChatMessageEventListener {
       onGroupMessageRead(groupMessageAcks: ChatGroupMessageAck[]): void {
           // Receive the onGroupMessageRead callback.
           console.log(`onGroupMessageRead: `, messages);
       }
       // ...
       }
       // Add a chat message event.
       const listener = new ChatMessageEvent();
       ChatClient.getInstance().chatManager.addMessageListener(listener);
       ```

    2. The sender sends a chat group message. Ensure that you set `needGroupAck` as `true`.

       ```typescript
       // Send a group message
       // Set needGroupAck as true to require a chat group message read receipt
       msg.needGroupAck = true;
       // Call sendMessage to send the group message
       ChatClient.getInstance()
       .chatManager.sendMessage(msg)
       .then(() => {
           // Print a log here if the message sending succeeds.
           console.log("send message success.");
       })
       .catch((reason) => {
           // Print a log here if the message sending fails.
           console.log("send message fail.", reason);
       });
       ```

    3. The chat group member reads the message and call `sendGroupMessageReadAck` to send a chat group message receipt. The SDK will trigger `onGroupMessageRead` on the sender's client.

       ```typescript
       // Send a chat group message read receipt
       // The ID of the message that requires a read receipt
       const msgId;
       // The chat group ID
       const groupId;
       // Call sendGroupMessageReadAck
       ChatClient.getInstance()
       .chatManager.sendGroupMessageReadAck(msgId, groupId)
       .then(() => {
           // Print a log here if the message sending succeeds.
           console.log("send message read success.");
       })
       .catch((reason) => {
           // Print a log here if the message sending fails.
           console.log("send message read fail.", reason);
       });
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="windows">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="windows" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-5]

    The Chat SDK uses `IChatManager` to provide message receipt. The following are the core methods:

    * `Options.RequireDeliveryAck`: Enable message delivery receipt.
    * `IChatManager.SendConversationReadAck`: Send a conversation read receipt.
    * `IChatManager.SendMessageReadAck`: Send a message read receipt.
    * `SendReadAckForGroupMessage`: Send a message read receipt for group chat.

    ## Prerequisites [#prerequisites-5]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-5]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-5]

    To send a message delivery receipt, take the following steps:

    1. The message sender sets `RequireDeliveryAck` in `ChatOptions` as `true` before sending the message:

       ```csharp
       Options.RequireDeliveryAck = true;
       ```

    2. Once the recipient receives the message, the SDK triggers `OnMessageDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient.

       ```csharp
       // Inherit and instantiate `IChatManagerDelegate`.
       public class ChatManagerDelegate : IChatManagerDelegate {
           // Occurs when the message is delivered.
           public void OnMessagesDelivered(List messages)
           {
           }
       }
       // Add the chat manager delegate.
       ChatManagerDelegate adelegate = new ChatManagerDelegate();
       SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
       // Remove the delegate.
       SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-5]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats-4]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    * Conversation read receipts

      Follow the steps to implement conversation read receipts in one-to-one chats.

      1. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `SendConversationReadAck` to send a conversation read receipt.

         ```csharp
         SDKClient.Instance.ChatManager.SendConversationReadAck(conversationId, new CallBack(
         onSuccess: () => {

         },
         onError:(code, desc) => {

         }
         ));
         ```

      2. The message sender listens for message events and receives the conversation read receipt in `OnConversationRead`.

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the conversation read receipt is received.
             // `from` indicates the message recipient that sends this receipt, and `to` indicates the message sender that receives this receipt.
             public void OnConversationRead(string from, string to)
             {
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Remove the delegate.
         SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
         ```

      <CalloutContainer type="info">
        <CalloutDescription>
          In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation to 0, and all other devices receive `OnConversationRead`.
        </CalloutDescription>
      </CalloutContainer>

    * Message read receipts

      To implement the message read receipt, take the following steps:

      1. Send a conversation read receipt when the recipient enters the conversation.

         ```csharp
         SDKClient.Instance.ChatManager.SendConversationReadAck(conversationId, new CallBack(
         onSuccess: () => {

         },
         onError:(code, desc) => {

         }
         ));
         ```

      2. When a new message arrives, send the message read receipt and add proper handling logics for the different message types.

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the message is received.
             public void OnMessageReceived(List messages)
             {
             ......
             sendReadAck(message);
             ......
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Send a message read receipt.
         public void sendReadAck(Message message) {
             // For a received message that has not sent a read receipt.
             if(message.Direction == MessageDirection.RECEIVE
             undefined message.MessageType == MessageType.Chat) {
                 MessageBodyType type = message.Body.Type;
                 // For attachment messages such as video and voice, send the message read receipt after the receiver clicks the files.
                 if(type == MessageBodyType.VIDEO || type == MessageBodyType.VOICE || type == MessageBodyType.FILE) {
                     return;
                 }
                 SDKClient.Instance.ChatManager.SendMessageReadAck(message.MsgId, new CallBack(
                 onSuccess: () => {

                 },
                 onError: (code, desc) => {
                 }
                 );
             }
         }
         ```

      3. The message sender listens for the message receipt:

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the message is read.
             public void OnMessagesRead(string from, string to)
             {
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Remove the delegate.
         SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
         ```

    #### Chat groups [#chat-groups-4]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default                        | Description                                                                                                                                                                                                                                |
    | :------------------------------------------------------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled                       | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                    |
    | Permission                                                                       | Group owner and administrators | By default, only the group owner and administrators can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission to regular group members.                       |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days                         | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                             |
    | Chat group size                                                                  | 500 members                    | This feature is available only to groups with up to 500 members. In other words, each message in a group can have up to 500 read receipts. If the upper limit is exceeded, the latest read receipt record will overwrite the earliest one. |
    | Maximum number of group messages that can have read receipts per day             | 500                            | A group can have up to 500 messages each day for which read receipts can be returned.                                                                                                                                                      |

    Follow the steps to implement read receipts for a chat group message:

    1. When sending a message, a group member can set whether to require a message read receipt.

       ```csharp
       // Set `IsNeedGroupAck` in `Message` as `true` when creating the message.
       Message msg = Message.CreateTextSendMessage("to", "hello world");
       msg.IsNeedGroupAck = true;
       ```

    2. After the group member reads the chat group message, call `SendReadAckForGroupMessage` from the group member's client to send a message read receipt:

       ```csharp
       void SendReadAckForGroupMessage(string messageId, string ackContent)
       {
           SDKClient.Instance.ChatManager.SendReadAckForGroupMessage(messageId, ackContent，callback: new CallBack(
               onSuccess: () =>
               {

               },
               onError: (code, desc) =>
               {

               }
           ));
       }
       ```

    3. The message sender listens for the message read receipt.

       ```csharp
       // Inherit and instantiate `IChatManagerDelegate`.
       public class ChatManagerDelegate : IChatManagerDelegate {
           // Occurs when the group message is read.
           public void OnGroupMessageRead(List list)
           {
           }
       }
       // Add a chat manager delegate.
       ChatManagerDelegate adelegate = new ChatManagerDelegate()
       SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
       ```

    4. The message sender can get the detailed information of the read receipt using `FetchGroupReadAcks`.

       ```csharp
       // messageId: The message ID.
       // pageSize: The page size. The value range is [1,50].
       // startAckId: The starting receipt ID for query. Set it as null for the first call of the method and the SDK retrieves from the latest receipt.
       SDKClient.Instance.ChatManager.FetchGroupReadAcks(messageId, groupId, startAckId, pageSize, new ValueCallBack>(
           onSuccess: (list) =>
           {
           // Updates the UI.
           },
           onError: (code, desc) =>
           {
           }
       ));
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="unity">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="unity" />

    The Chat SDK provides the message read receipt feature that allows the user, after sending a message, to know whether the message is read. The feature is available to both one-to-one chats and group chats.

    * Message delivery receipt: Available only to one-to-one chats.
    * Message read receipt: Available to both one-to-one chats and group chats.

    ## Understand the tech [#understand-the-tech-6]

    The Chat SDK uses `IChatManager` to provide message receipt. The following are the core methods:

    * `Options.RequireDeliveryAck`: Enable message delivery receipt.
    * `IChatManager.SendConversationReadAck`: Send a conversation read receipt.
    * `IChatManager.SendMessageReadAck`: Send a message read receipt.
    * `SendReadAckForGroupMessage`: Send a message read receipt for group chat.

    ## Prerequisites [#prerequisites-6]

    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](../../../../get-started-sdk).
    * You understand the API call frequency limits as described in [Limitations](../../limitations).
    * Message read receipts for chat groups are not enabled by default. To use this feature, contact [support@agora.io](mailto\:support@agora.io).

    ## Implementation [#implementation-6]

    This section introduces how to implement message delivery and read receipts in your chat app.

    ### Message delivery receipts [#message-delivery-receipts-6]

    To send a message delivery receipt, take the following steps:

    1. The message sender sets `RequireDeliveryAck` in `ChatOptions` as `true` before sending the message:

       ```csharp
       Options.RequireDeliveryAck = true;
       ```

    2. Once the recipient receives the message, the SDK triggers `OnMessageDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient.

       ```csharp
       // Inherit and instantiate `IChatManagerDelegate`.
       public class ChatManagerDelegate : IChatManagerDelegate {
           // Occurs when the message is delivered.
           public void OnMessagesDelivered(List messages)
           {
           }
       }
       // Add the chat manager delegate.
       ChatManagerDelegate adelegate = new ChatManagerDelegate();
       SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
       // Remove the delegate.
       SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
       ```

    ### Conversation and message read receipts [#conversation-and-message-read-receipts-6]

    In both one-to-one chats and group chats, you can use message read receipts to notify the message sender that the message has been read. To minimize the method call for message read receipts, the SDK also supports conversation read receipts in one-to-one chats.

    #### One-to-one chats [#one-to-one-chats-5]

    In one-to-one chats, the SDK supports sending both the conversation read receipts and message read receipts. Agora recommends using conversation read receipts if the new message arrives when the message recipient has not entered the conversation UI.

    * Conversation read receipts

      Follow the steps to implement conversation read receipts in one-to-one chats.

      1. When a user enters the conversation UI, check whether the conversation contains unread messages. If yes, call `SendConversationReadAck` to send a conversation read receipt.

         ```csharp
         SDKClient.Instance.ChatManager.SendConversationReadAck(conversationId, new CallBack(
         onSuccess: () => {

         },
         onError:(code, desc) => {

         }
         ));
         ```

      2. The message sender listens for message events and receives the conversation read receipt in `OnConversationRead`.

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the conversation read receipt is received.
             // `from` indicates the message recipient that sends this receipt, and `to` indicates the message sender that receives this receipt.
             public void OnConversationRead(string from, string to)
             {
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Remove the delegate.
         SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
         ```

      <CalloutContainer type="info">
        <CalloutDescription>
          In use-cases where a user is logged in multiple devices, if the user sends a conversation read receipt from one device, the server sets the count of unread messages in the conversation to 0, and all other devices receive `OnConversationRead`.
        </CalloutDescription>
      </CalloutContainer>

    * Message read receipts

      To implement the message read receipt, take the following steps:

      1. Send a conversation read receipt when the recipient enters the conversation.

         ```csharp
         SDKClient.Instance.ChatManager.SendConversationReadAck(conversationId, new CallBack(
         onSuccess: () => {

         },
         onError:(code, desc) => {

         }
         ));
         ```

      2. When a new message arrives, send the message read receipt and add proper handling logics for the different message types.

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the message is received.
             public void OnMessageReceived(List messages)
             {
             ......
             sendReadAck(message);
             ......
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Send a message read receipt.
         public void sendReadAck(Message message) {
             // For a received message that has not sent a read receipt.
             if(message.Direction == MessageDirection.RECEIVE
             undefined message.MessageType == MessageType.Chat) {
                 MessageBodyType type = message.Body.Type;
                 // For attachment messages such as video and voice, send the message read receipt after the receiver clicks the files.
                 if(type == MessageBodyType.VIDEO || type == MessageBodyType.VOICE || type == MessageBodyType.FILE) {
                     return;
                 }
                 SDKClient.Instance.ChatManager.SendMessageReadAck(message.MsgId, new CallBack(
                 onSuccess: () => {

                 },
                 onError: (code, desc) => {
                 }
                 );
             }
         }
         ```

      3. The message sender listens for the message receipt:

         ```csharp
         // Inherit and instantiate `IChatManagerDelegate`.
         public class ChatManagerDelegate : IChatManagerDelegate {
             // Occurs when the message is read.
             public void OnMessagesRead(string from, string to)
             {
             }
         }
         // Add a chat manager delegate.
         ChatManagerDelegate adelegate = new ChatManagerDelegate()
         SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
         // Remove the delegate.
         SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
         ```

    #### Chat groups [#chat-groups-5]

    For a group chat, group members can determine whether to require message read receipts when sending a message. If yes, after a group member reads the message, the SDK sends a read receipt. In a group chat, the number of message read receipts that are sent for the message refers to the number of group members that have read this message.

    The following table shows the restrictions of this feature:

    | Feature Restriction                                                              | Default                        | Description                                                                                                                                                                                                                                |
    | :------------------------------------------------------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Enabling the function                                                            | Disabled                       | To use this feature, contact [support@agora.io](mailto\:support@agora.io) to enable it.                                                                                                                                                    |
    | Permission                                                                       | Group owner and administrators | By default, only the group owner and administrators can request read receipts when sending a message. You can contact [support@agora.io](mailto\:support@agora.io) to grant the permission to regular group members.                       |
    | Number of days before read receipts cannot be returned after the message is sent | 3 days                         | The server no longer records the group members that read the message three days after it is sent, nor sends the read receipts.                                                                                                             |
    | Chat group size                                                                  | 500 members                    | This feature is available only to groups with up to 500 members. In other words, each message in a group can have up to 500 read receipts. If the upper limit is exceeded, the latest read receipt record will overwrite the earliest one. |
    | Maximum number of group messages that can have read receipts per day             | 500                            | A group can have up to 500 messages each day for which read receipts can be returned.                                                                                                                                                      |

    Follow the steps to implement read receipts for a chat group message:

    1. When sending a message, a group member can set whether to require a message read receipt.

       ```csharp
       // Set `IsNeedGroupAck` in `Message` as `true` when creating the message.
       Message msg = Message.CreateTextSendMessage("to", "hello world");
       msg.IsNeedGroupAck = true;
       ```

    2. After the group member reads the chat group message, call `SendReadAckForGroupMessage` from the group member's client to send a message read receipt:

       ```csharp
       void SendReadAckForGroupMessage(string messageId, string ackContent)
       {
           SDKClient.Instance.ChatManager.SendReadAckForGroupMessage(messageId, ackContent，callback: new CallBack(
               onSuccess: () =>
               {

               },
               onError: (code, desc) =>
               {

               }
           ));
       }
       ```

    3. The message sender listens for the message read receipt.

       ```csharp
       // Inherit and instantiate `IChatManagerDelegate`.
       public class ChatManagerDelegate : IChatManagerDelegate {
           // Occurs when the group message is read.
           public void OnGroupMessageRead(List list)
           {
           }
       }
       // Add a chat manager delegate.
       ChatManagerDelegate adelegate = new ChatManagerDelegate()
       SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
       ```

    4. The message sender can get the detailed information of the read receipt using `FetchGroupReadAcks`.

       ```csharp
          // messageId: The message ID.
          // pageSize: The page size. The value range is [1,50].
          // startAckId: The starting receipt ID for query. Set it as null for the first call of the method and the SDK retrieves from the latest receipt.
       SDKClient.Instance.ChatManager.FetchGroupReadAcks(messageId, groupId, startAckId, pageSize, new ValueCallBack>(
           onSuccess: (list) =>
           {
           // Updates the UI.
           },
           onError: (code, desc) =>
           {
           }
       ));
       ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
