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

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

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) =>
           {
           }
       ));
       ```

    
  
      
  
