# Thread messages (/en/realtime-media/im/build/build-groups-rooms-and-threads/threading/thread-messages/unity)

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

Threads enable users to create a separate conversation from a specific message within a chat group to keep the main chat uncluttered.

    This page shows how to use the Chat SDK to send, receive, recall, and retrieve thread messages in your app.

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

    The Agora Chat SDK allows you to implement the following features:

    ## Prerequisites [#prerequisites-5]

    Before proceeding, ensure that you meet the following requirements:

    * You have initialized the Chat SDK. For details, see [SDK quickstart](../../../get-started-sdk).
    * You understand the call frequency limit of the Chat APIs supported by different pricing plans as described in [Limitations](../../limitations).

    <CalloutContainer type="info">
      <CalloutDescription>
        The thread feature is supported by all types of [Pricing Plans](../../../reference/pricing-plan-details) and is enabled by default once you have enabled Chat in [Agora Console](https://console.agora.io/v2).
      </CalloutDescription>
    </CalloutContainer>

    ## Implementation [#implementation-5]

    This section describes how to call the APIs provided by the Chat SDK to implement thread features.

    ### Send a thread message [#send-a-thread-message-5]

    Send a thread message is similar to send a message in a chat group. The difference lies in the `IsThread` field, as shown in the following code sample:

    ```csharp
    // Creates a text message. Sets `chatThreadId` to the thread ID and `content` to the message content.
    Message msg = Message.CreateTextSendMessage(chatThreadId, content);
    // Sets the message type. For thread messages, set `ChatType` as `GroupChat`.
    msg.MessageType = MessageType.Group
    // Set the `IsThread` flag as `true`.
    mmsg.IsThread = true;
    // You can create an `CallBack` instance to get the status of message sending. You can update the message status in the callback, such as the information to display when users failed to send a message.
    SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
        onSuccess: () => {
            Debug.Log($"SendTxtMessage success. msgid:{msg.MsgId}");
        },
        onProgress: (progress) => {
            Debug.Log($"SendTxtMessage progress :{progress.ToString()}");
        },
        onError: (code, desc) => {
            Debug.Log($"SendTxtMessage failed, code:{code}, desc:{desc}");
        }
    ));
    ```

    For more information about sending a message, see [Send Messages](../../build-core-messaging/messages/send-receive-messages#send-a-text-message).

    ### Receive a thread message [#receive-a-thread-message-5]

    Once a thread has a new message, all chat group members receive the `IChatThreadManagerDelegate#OnUpdateMyThread` callback. Thread members can also listen for the `IChatManagerDelegate#OnMessagesReceived` callback to receive thread messages, as shown in the following code sample:

    ```csharp
    // Inherits and implements `IChatManagerDelegate`.
    public class ChatManagerDelegate : IChatManagerDelegate {
        // Implements the `MessagesReceived` callback.
        public void OnMessagesReceived(List messages)
        {
          // When receiving messages, iterates through the message list and parses and displays the message.
        }
    }
    // Registers an listener.
    ChatManagerDelegate adelegate = new ChatManagerDelegate();
    SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
    // Removes the listener.
    SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
    ```

    For more information about receiving a message, see [Receive Messages](../../build-core-messaging/messages/send-receive-messages#receive-a-message).

    ### Recall a thread message [#recall-a-thread-message-5]

    Send a thread message is similar to send a message in a chat group. The difference lies in the `isChatThread` field.

    Once a message is recalled in a thread, all chat group members receive the `IChatThreadManagerDelegate#OnUpdateMyThread` callback. Thread members can also listen for the `IChatManagerDelegate#OnMessagesRecalled` callback, as shown in the following code sample:

    ```csharp
    // Inherits and implements IChatManagerDelegate.
    public class ChatManagerDelegate : IChatManagerDelegate {
        // Implements the `OnMessagesRecalled` callback.
        public void OnMessagesRecalled(List messages)
        {
          // When receiving messages, iterates through the message list and parses and displays the message.
        }
    }
    // Registers an listener.
    ChatManagerDelegate adelegate = new ChatManagerDelegate();
    SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
    // Removes the listener.
    SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);
    ```

    For more information about recalling a message, see [Recall Messages](../../build-core-messaging/messages/send-receive-messages#recall-a-message).

    ### Retrieve thread messages [#retrieve-thread-messages-4]

    You can retrieve thread messages locally or from the server, depending on your production environment.

    You can check `Conversation#IsThread()` to determine whether the current conversation is a thread conversation.

    #### Retrieve messages of a thread from the server [#retrieve-messages-of-a-thread-from-the-server-5]

    You can call `ChatManager#FetchHistoryMessagesFromServer` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

    ```csharp
    SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(threadId, ConversationType.Group, startMsgId, pageSize, MessageSearchDirection.DOWN, new ValueCallBack>(
              onSuccess: (result) =>
              {
                  foreach (var msg in result.Data)
                  {
                      //process every msg
                  }
              },
              onError: (code, desc) =>
              {
              }
          ));
    ```

    #### Retrieve messages of a thread locally [#retrieve-messages-of-a-thread-locally-4]

    By calling `ChatManager#LoadAllConversations`, you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

    ```csharp
    // Specifies the conversation type by setting `ConversationType.Group` and setting `isChatThread` as `true`.
    Conversation conversation = SDKClient.Instance.ChatManager.GetConversation(chatThreadId, EMConversationType.GroupChat, createIfNotExists, isChatThread);
    // If you want to handle thread messages from your local database, use the following methods to retrieve the messages. The SDK automatically loads and stores the retrieved messages to the memory.
    conversation.LoadMessages(startMsgId, count, direct, new ValueCallBack>(
        onSuccess: (list) => {
            Console.WriteLine($"LoadMessages found {list.Count} messages");
            foreach (var it in list)
            {
                Debug.Log($"message id: {it.MsgId}");
            }
        },
        onError: (code, desc) => {
            Debug.Log($"LoadMessages failed, code:{code}, desc:{desc}");
        }
    ));
    ```

    
  
      
  
