> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-rn-guide-message-privately.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Receive A Message

> Receive real-time messages, fetch missed and unread messages, retrieve message history, search messages, and get unread counts using the CometChat Android SDK.

<Accordion title="AI Integration Quick Reference">
  | Field           | Value                                                                               |
  | --------------- | ----------------------------------------------------------------------------------- |
  | Key Classes     | `CometChat.MessageListener`, `MessagesRequestBuilder`                               |
  | Key Methods     | `addMessageListener()`, `fetchPrevious()`, `fetchNext()`, `getUnreadMessageCount()` |
  | Listener Events | `onTextMessageReceived`, `onMediaMessageReceived`, `onCustomMessageReceived`        |
  | Prerequisites   | SDK initialized, user logged in                                                     |
</Accordion>

Receiving messages with CometChat has two parts:

1. Adding a [real-time listener](#real-time-messages) to receive messages while your app is running
2. Fetching [missed](#missed-messages), [unread](#unread-messages), or [historical](#message-history) messages when your app starts up or the user scrolls back

## Real-Time Messages

Register a `MessageListener` to receive incoming messages as they arrive. For every activity or fragment you wish to receive messages in, register the listener using `addMessageListener()`. We suggest adding it in the `onResume()` method.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    private String listenerID = "UNIQUE_LISTENER_ID";

    CometChat.addMessageListener(listenerID, new CometChat.MessageListener() {
      @Override
      public void onTextMessageReceived(TextMessage textMessage) {
          Log.d(TAG, "Text message received successfully: " + textMessage.toString());
      }

      @Override
      public void onMediaMessageReceived(MediaMessage mediaMessage) {
          Log.d(TAG, "Media message received successfully: " + mediaMessage.toString());
      }

      @Override
      public void onCustomMessageReceived(CustomMessage customMessage) {
          Log.d(TAG, "Custom message received successfully: " + customMessage.toString());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val listenerID:String = "UNIQUE_LISTENER_ID"

    CometChat.addMessageListener(listenerID, object : MessageListener() {
      override fun onTextMessageReceived(textMessage: TextMessage) {
          Log.d(TAG, "Text message received successfully: $textMessage")
      }

      override fun onMediaMessageReceived(mediaMessage: MediaMessage) {
          Log.d(TAG, "Media message received successfully: $mediaMessage")
      }

      override fun onCustomMessageReceived(customMessage: CustomMessage) {
          Log.d(TAG, "Custom message received successfully: $customMessage")
      }
    })
    ```
  </Tab>
</Tabs>

| Parameter    | Description                                                                                    |
| ------------ | ---------------------------------------------------------------------------------------------- |
| `listenerID` | An ID that uniquely identifies that listener. We recommend using the activity or fragment name |

Remove the listener when you no longer need it. Typically, this can be added in the `onPause()` method.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    private String listenerID = "UNIQUE_LISTENER_ID";

    CometChat.removeMessageListener(listenerID);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val listenerID:String = "UNIQUE_LISTENER_ID"

    CometChat.removeMessageListener(listenerID)
    ```
  </Tab>
</Tabs>

<Warning>
  Always remove listeners when they're no longer needed (e.g., in `onPause()`). Failing to do so can cause memory leaks and duplicate event handling.
</Warning>

<Warning>
  As a sender, you will not receive your own message in a real-time message event. However, if a user is logged-in using multiple devices, they will receive an event for their own message in other devices.
</Warning>

## Missed Messages

Fetch messages that arrived while your app was offline. Use `getLastDeliveredMessageId()` to find where you left off, then call `fetchNext()` to get everything after that point. Call `fetchNext()` repeatedly on the same request object to paginate.

<Tabs>
  <Tab title="One-on-One">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private int latestId = CometChat.getLastDeliveredMessageId();
        private String UID = "cometchat-uid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setMessageId(latestId)
              .setLimit(limit)
              .setUID(UID)
              .build();

        messagesRequest.fetchNext(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " +
                              ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " +
                              ((MediaMessage) message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        lateinit var messagesRequest: MessagesRequest
        val latestId = CometChat.getLastDeliveredMessageId()
        val limit: Int = 30
        val UID: String = "cometchat-uid-1"

        val messagesRequest = MessagesRequestBuilder()
          .setMessageId(latestId)
          .setLimit(limit)
          .setUID(UID)
          .build()

        messagesRequest.fetchNext(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(
                          TAG, "Text message received successfully: " +
                                  message.toString()
                      )
                  } else if (message is MediaMessage) {
                      Log.d(
                          TAG, "Media message received successfully: " +
                                  message.toString()
                      )
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: " + e.message)
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Group">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private int latestId = CometChat.getLastDeliveredMessageId();
        private String GUID = "cometchat-guid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setMessageId(latestId)
              .setLimit(limit)
              .setGUID(GUID)
              .build();

        messagesRequest.fetchNext(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        lateinit var messagesRequest: MessagesRequest
        val latestId = CometChat.getLastDeliveredMessageId()
        val limit: Int = 30
        val GUID: String = "cometchat-uid-1"

        messagesRequest = MessagesRequestBuilder()
          .setMessageId(latestId)
          .setLimit(limit)
          .setGUID(GUID)
          .build()

        messagesRequest.fetchNext(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(
                          TAG, "Text message received successfully: " +
                                  message.toString()
                      )
                  } else if (message is MediaMessage) {
                      Log.d(
                          TAG, "Media message received successfully: " +
                                  message.toString()
                      )
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: " + e.message)
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

## Unread Messages

Fetch unread messages by adding `setUnread(true)` to the builder. Use `fetchPrevious()` to retrieve them.

<Tabs>
  <Tab title="One-on-One">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        String UID = "cometchat-uid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setUnread(true)
              .setLimit(20)
              .setUID(UID)
              .build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " +((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " +((MediaMessage) message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val UID:String = "cometchat-uid-1"

        val messagesRequest = MessagesRequestBuilder()
          .setUnread(true)
          .setLimit(20)
          .setUID(UID)
          .build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: " + e.message)
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Group">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        String GUID = "cometchat-guid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setUnread(true)
              .setLimit(20)
              .setGUID(GUID)
              .build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val GUID:String = "cometchat-guid-1"

        val messagesRequest = MessagesRequestBuilder()
          .setUnread(true)
          .setLimit(20)
          .setGUID(GUID)
          .build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: " + e.message)
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

<Note>
  The list of messages received is in the form of objects of [`BaseMessage`](/sdk/reference/messages#basemessage) class. A `BaseMessage` can either be an object of the [`TextMessage`](/sdk/reference/messages#textmessage), [`MediaMessage`](/sdk/reference/messages#mediamessage), [`CustomMessage`](/sdk/reference/messages#custommessage), [`Action`](/sdk/reference/messages#action) or [`Call`](/sdk/reference/messages#call) class. You can use the `instanceOf` operator to check the type of object.
</Note>

## Message History

Fetch the full conversation history using `fetchPrevious()`. Call it repeatedly on the same request object to paginate — useful for implementing upward scrolling.

<Tabs>
  <Tab title="One-on-One">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private String UID = "cometchat-uid-1"

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setLimit(limit)
              .setUID(UID)
              .build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val limit: Int = 30
        val UID: String = "cometchat-uid-1"

        val messagesRequest = MessagesRequestBuilder()
          .setLimit(limit)
          .setUID(UID)
          .build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: " + e.message)
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Group">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private String GUID = "cometchat-guid-1"

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder()
              .setLimit(limit)
              .setGUID(GUID)
              .build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val limit: Int = 30
        val GUID: String = "cometchat-guid-1"

        val messagesRequest = MessagesRequestBuilder()
          .setLimit(limit)
          .setGUID(GUID)
          .build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: ${e.message}")
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

## Search Messages

Add `setSearchKeyword()` to the builder to filter messages by keyword.

<Tabs>
  <Tab title="One-on-One">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private String UID = "cometchat-uid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder().setSearchKeyword("Hello").setUID(UID).setLimit(limit).build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val limit: Int = 30
        val UID: String = "cometchat-uid-1"

        val messagesRequest = MessagesRequestBuilder().setSearchKeyword("Hello").setUID(UID).setLimit(limit).build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: ${e.message}")
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Group">
    <Tabs>
      <Tab title="Java">
        ```java theme={null}
        private int limit = 30;
        private String GUID = "cometchat-guid-1";

        MessagesRequest messagesRequest = new MessagesRequest.MessagesRequestBuilder().setSearchKeyword("Hello").setGUID(GUID).setLimit(limit).build();

        messagesRequest.fetchPrevious(new CometChat.CallbackListener<List<BaseMessage>>() {
          @Override
          public void onSuccess(List<BaseMessage> list) {
              for (BaseMessage message : list) {
                  if (message instanceof TextMessage) {
                      Log.d(TAG, "Text message received successfully: " + ((TextMessage) message).toString());
                  } else if (message instanceof MediaMessage) {
                      Log.d(TAG, "Media message received successfully: " + ((MediaMessage)message).toString());
                  }
              }
          }

          @Override
          public void onError(CometChatException e) {
              Log.d(TAG, "Message fetching failed with exception: " + e.getMessage());
          }
        });
        ```
      </Tab>

      <Tab title="Kotlin">
        ```kotlin theme={null}
        val limit = 30
        val GUID = "cometchat-guid-1"

        val messagesRequest = MessagesRequestBuilder().setSearchKeyword("Hello").setGUID(GUID).setLimit(limit).build()

        messagesRequest.fetchPrevious(object : CallbackListener<List<BaseMessage?>>() {
          override fun onSuccess(list: List<BaseMessage?>) {
              for (message in list) {
                  if (message is TextMessage) {
                      Log.d(TAG, "Text message received successfully: $message")
                  } else if (message is MediaMessage) {
                      Log.d(TAG, "Media message received successfully: $message")
                  }
              }
          }

          override fun onError(e: CometChatException) {
              Log.d(TAG, "Message fetching failed with exception: ${e.message}")
          }
        })
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

### Search Capabilities

By default, search only matches message text. With `Conversation & Advanced Search` enabled, it also matches file names, mentions, and MIME types.

| Feature          | Basic Search | Advanced Search |
| ---------------- | ------------ | --------------- |
| Text search      | ✅            | ✅               |
| File name search | ❌            | ✅               |
| Mentions search  | ❌            | ✅               |
| Mime type search | ❌            | ✅               |

<Note>
  `Conversation & Advanced Search` is available on `Advanced` and `Custom` [plans](https://www.cometchat.com/pricing). Enable it from the [CometChat Dashboard](https://app.cometchat.com) under Chats → Settings → General Configuration.
</Note>

## Unread Message Count

CometChat provides several methods to get unread counts at different scopes. All return results via a callback listener with a `HashMap` mapping IDs to counts.

Each method accepts an optional boolean parameter to exclude messages from blocked users.

| Method                                | Scope                     | Returns                            |
| ------------------------------------- | ------------------------- | ---------------------------------- |
| `getUnreadMessageCountForUser(UID)`   | Single user conversation  | `HashMap<UID, count>`              |
| `getUnreadMessageCountForGroup(GUID)` | Single group conversation | `HashMap<GUID, count>`             |
| `getUnreadMessageCountForAllUsers()`  | All user conversations    | `HashMap<UID, count>`              |
| `getUnreadMessageCountForAllGroups()` | All group conversations   | `HashMap<GUID, count>`             |
| `getUnreadMessageCount()`             | Everything                | `HashMap<"user"/"group", HashMap>` |

### Single Conversation

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    // One-on-one
    private String UID = "cometchat-uid-1";

    CometChat.getUnreadMessageCountForUser(UID, new CometChat.CallbackListener<HashMap<String, Integer>>() {
      @Override
      public void onSuccess(HashMap<String, Integer> stringIntegerHashMap) {
          // handle success
      }

      @Override
      public void onError(CometChatException e) {
          // handle error
      }
    });

    // Group
    private String GUID = "cometchat-guid-1";

    CometChat.getUnreadMessageCountForGroup(GUID, new CometChat.CallbackListener<HashMap<String, Integer>>(){
      @Override
      public void onSuccess(HashMap<String, Integer> stringIntegerHashMap) {
          // handle success
      }

      @Override
      public void onError(CometChatException e) {
          // handle error
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    // One-on-one
    val UID: String = "cometchat-uid-1"

    CometChat.getUnreadMessageCountForUser(UID, object : CallbackListener<HashMap<String?, Int?>?>() {
      override fun onSuccess(stringIntegerHashMap: HashMap<String?, Int?>?) {
          // handle success
      }

      override fun onError(e: CometChatException) {
          // handle error
      }
    })

    // Group
    val GUID: String = "cometchat-guid-1"

    CometChat.getUnreadMessageCountForGroup(GUID, object : CallbackListener<HashMap<String?, Int?>?>() {
      override fun onSuccess(stringIntegerHashMap: HashMap<String?, Int?>?) {
          // handle success
      }

      override fun onError(e: CometChatException) {
          // handle error
      }
    })
    ```
  </Tab>
</Tabs>

### All Conversations

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    // All users and groups combined
    CometChat.getUnreadMessageCount(new CometChat.CallbackListener<HashMap<String, HashMap<String, Integer>>>() {
      @Override
      public void onSuccess(HashMap<String, HashMap<String, Integer>> stringHashMapHashMap) {
          // handle success
      }

      @Override
      public void onError(CometChatException e) {
          // handle error
      }
    });

    // All user conversations only
    CometChat.getUnreadMessageCountForAllUsers(new CometChat.CallbackListener<HashMap<String, Integer>>() {
      @Override
      public void onSuccess(HashMap<String, Integer> stringIntegerHashMap) {
          // Handle Success
      }

      @Override
      public void onError(CometChatException e) {
          // Handle Error
      }
    });

    // All group conversations only
    CometChat.getUnreadMessageCountForAllGroups(new CometChat.CallbackListener<HashMap<String, Integer>>() {
      @Override
      public void onSuccess(HashMap<String, Integer> stringIntegerHashMap) {
          // Handle success
      }

      @Override
      public void onError(CometChatException e) {
          // Handle Error
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    // All users and groups combined
    CometChat.getUnreadMessageCount(object : CallbackListener<HashMap<String?, HashMap<String?, Int?>?>?>() {
      override fun onSuccess(stringHashMapHashMap: HashMap<String?, HashMap<String?, Int?>?>?) {
          // handle success
      }

      override fun onError(e: CometChatException) {
          // handle error
      }
    })

    // All user conversations only
    CometChat.getUnreadMessageCountForAllUsers(object : CometChat.CallbackListener<HashMap<String, Int>>() {
      override fun onSuccess(stringIntegerHashMap: HashMap<String, Int>) {
          Log.d(TAG,"onSuccess: ${stringIntegerHashMap.size}")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG,"onError: ${e.message}")
      }
    })

    // All group conversations only
    CometChat.getUnreadMessageCountForAllGroups(object : CometChat.CallbackListener<HashMap<String, Int>>() {
      override fun onSuccess(stringIntegerHashMap: HashMap<String, Int>) {
          Log.d(TAG,"onSuccess: ${stringIntegerHashMap.size}")
      }

      override fun onError(e: CometChatException) {
          Log.e(TAG,"onError: ${e.message}")
      }
    })
    ```
  </Tab>
</Tabs>

### Excluding Blocked Users

Pass `true` as the second argument to any of the methods above to ignore messages from blocked users:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CometChat.getUnreadMessageCountForUser(UID, true, Callbacks);
    CometChat.getUnreadMessageCountForGroup(GUID, true, Callbacks);
    CometChat.getUnreadMessageCount(true, Callbacks);
    CometChat.getUnreadMessageCountForAllUsers(true, Callbacks);
    CometChat.getUnreadMessageCountForAllGroups(true, Callbacks);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    CometChat.getUnreadMessageCountForUser(UID, true, Callbacks)
    CometChat.getUnreadMessageCountForGroup(GUID, true, Callbacks)
    CometChat.getUnreadMessageCount(true, Callbacks)
    CometChat.getUnreadMessageCountForAllUsers(true, Callbacks)
    CometChat.getUnreadMessageCountForAllGroups(true, Callbacks)
    ```
  </Tab>
</Tabs>

## Get Message Details

Use `getMessageDetails()` to fetch a specific message by its ID. Returns the full message object ([`TextMessage`](/sdk/reference/messages#textmessage), [`MediaMessage`](/sdk/reference/messages#mediamessage), [`CustomMessage`](/sdk/reference/messages#custommessage), or other [`BaseMessage`](/sdk/reference/messages#basemessage) subclass).

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    int messageId = MESSAGE_ID;

    CometChat.getMessageDetails(messageId, new CometChat.CallbackListener<BaseMessage>() {
      @Override
      public void onSuccess(BaseMessage message) {
          Log.d(TAG, "Message details fetched: " + message.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Error fetching message details: " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val messageId: Int = MESSAGE_ID

    CometChat.getMessageDetails(messageId, object : CometChat.CallbackListener<BaseMessage>() {
      override fun onSuccess(message: BaseMessage) {
          Log.d(TAG, "Message details fetched: $message")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Error fetching message details: ${e.message}")
      }
    })
    ```
  </Tab>
</Tabs>

| Parameter   | Type  | Description                    |
| ----------- | ----- | ------------------------------ |
| `messageId` | `int` | The ID of the message to fetch |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Delivery & Read Receipts" icon="check-double" href="/sdk/android/delivery-read-receipts">
    Track when messages are delivered and read by recipients
  </Card>

  <Card title="Typing Indicators" icon="keyboard" href="/sdk/android/typing-indicators">
    Show real-time typing status in conversations
  </Card>

  <Card title="Message History" icon="clock-rotate-left" href="/sdk/android/additional-message-filtering">
    Advanced filtering options for message history
  </Card>

  <Card title="Send Message" icon="paper-plane" href="/sdk/android/send-message">
    Send text, media, and custom messages
  </Card>
</CardGroup>

## Message Payload Structure

<Accordion title="BaseMessage Object">
  The `BaseMessage` object returned by SDK methods contains the following fields. `TextMessage`, `MediaMessage`, and `CustomMessage` extend this base structure with additional type-specific fields.

  | Parameter            | Type                                           | Description                                                                           |
  | -------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------- |
  | `id`                 | long                                           | Unique message identifier                                                             |
  | `muid`               | String                                         | Developer-defined message ID for deduplication                                        |
  | `sender`             | [User](#user-object)                           | User who sent the message                                                             |
  | `receiver`           | AppEntity                                      | Message receiver ([User](#user-object) or [Group](#group-object))                     |
  | `receiverUid`        | String                                         | Receiver's unique identifier                                                          |
  | `type`               | String                                         | Message type. Values: `"text"`, `"image"`, `"video"`, `"audio"`, `"file"`, `"custom"` |
  | `receiverType`       | String                                         | Type of receiver. Values: `"user"`, `"group"`                                         |
  | `category`           | String                                         | Message category. Values: `"message"`, `"action"`, `"call"`, `"custom"`               |
  | `sentAt`             | long                                           | Unix timestamp when message was sent                                                  |
  | `deliveredAt`        | long                                           | Unix timestamp when message was delivered                                             |
  | `readAt`             | long                                           | Unix timestamp when message was read                                                  |
  | `metadata`           | JSONObject                                     | Custom message metadata set by developer                                              |
  | `readByMeAt`         | long                                           | Unix timestamp when logged-in user read the message                                   |
  | `deliveredToMeAt`    | long                                           | Unix timestamp when message was delivered to logged-in user                           |
  | `deletedAt`          | long                                           | Unix timestamp when message was deleted (0 if not deleted)                            |
  | `editedAt`           | long                                           | Unix timestamp when message was edited (0 if not edited)                              |
  | `deletedBy`          | String                                         | UID of user who deleted the message (null if not deleted)                             |
  | `editedBy`           | String                                         | UID of user who edited the message (null if not edited)                               |
  | `updatedAt`          | long                                           | Unix timestamp of last message update                                                 |
  | `conversationId`     | String                                         | Associated conversation identifier                                                    |
  | `parentMessageId`    | long                                           | Parent message ID for threaded messages (0 if not a reply)                            |
  | `replyCount`         | int                                            | Number of replies in thread                                                           |
  | `unreadRepliesCount` | int                                            | Number of unread replies in thread                                                    |
  | `mentionedUsers`     | Array\<[User](#user-object)>                   | List of users mentioned in the message                                                |
  | `hasMentionedMe`     | boolean                                        | Whether the logged-in user is mentioned                                               |
  | `reactions`          | Array\<[ReactionCount](#reactioncount-object)> | List of reaction counts on the message                                                |
  | `rawMessage`         | JSONObject                                     | Raw JSON message data                                                                 |
  | `quotedMessageId`    | long                                           | ID of the quoted message (0 if not quoting)                                           |
  | `quotedMessage`      | BaseMessage                                    | The quoted message object (null if not quoting)                                       |

  **Sample BaseMessage Object:**

  ```json theme={null}
  {
    "id": 12345,
    "muid": "msg_abc123",
    "sender": {
      "uid": "user_123",
      "name": "John Doe",
      "avatar": "https://example.com/avatar.png",
      "status": "online",
      "role": "default",
      "lastActiveAt": 1699900000
    },
    "receiver": {
      "uid": "user_456",
      "name": "Jane Smith",
      "avatar": "https://example.com/avatar2.png"
    },
    "receiverUid": "user_456",
    "type": "text",
    "receiverType": "user",
    "category": "message",
    "sentAt": 1699900000,
    "deliveredAt": 1699900001,
    "readAt": 1699900002,
    "metadata": {
      "priority": "high",
      "customField": "value"
    },
    "readByMeAt": 1699900002,
    "deliveredToMeAt": 1699900001,
    "deletedAt": 0,
    "editedAt": 0,
    "deletedBy": null,
    "editedBy": null,
    "updatedAt": 1699900000,
    "conversationId": "user_123_user_456",
    "parentMessageId": 0,
    "replyCount": 5,
    "unreadRepliesCount": 2,
    "mentionedUsers": [],
    "hasMentionedMe": false,
    "reactions": [
      {
        "reaction": "👍",
        "count": 3,
        "reactedByMe": true
      }
    ],
    "rawMessage": {},
    "quotedMessageId": 0,
    "quotedMessage": null
  }
  ```
</Accordion>

<Accordion title="User Object">
  The nested `User` object (used in `sender`, `receiver`, `mentionedUsers`) contains:

  | Parameter       | Type           | Description                                            |
  | --------------- | -------------- | ------------------------------------------------------ |
  | `uid`           | String         | Unique identifier of the user                          |
  | `name`          | String         | Display name of the user                               |
  | `avatar`        | String         | URL to user's profile picture                          |
  | `link`          | String         | URL to user's profile page                             |
  | `role`          | String         | User role for access control                           |
  | `metadata`      | JSONObject     | Custom data set by developer                           |
  | `status`        | String         | User online status. Values: `"online"`, `"offline"`    |
  | `statusMessage` | String         | Custom status message                                  |
  | `lastActiveAt`  | long           | Unix timestamp of last activity                        |
  | `hasBlockedMe`  | boolean        | Whether this user has blocked the logged-in user       |
  | `blockedByMe`   | boolean        | Whether the logged-in user has blocked this user       |
  | `tags`          | Array\<String> | List of tags for user identification                   |
  | `deactivatedAt` | long           | Unix timestamp when user was deactivated (0 if active) |
</Accordion>

<Accordion title="Group Object">
  The nested `Group` object (used in `receiver` for group messages) contains:

  | Parameter      | Type           | Description                                                              |
  | -------------- | -------------- | ------------------------------------------------------------------------ |
  | `guid`         | String         | Unique identifier of the group                                           |
  | `name`         | String         | Display name of the group                                                |
  | `type`         | String         | Group type. Values: `"public"`, `"private"`, `"password"`                |
  | `icon`         | String         | URL to group icon                                                        |
  | `description`  | String         | Group description                                                        |
  | `owner`        | String         | UID of group owner                                                       |
  | `metadata`     | JSONObject     | Custom data set by developer                                             |
  | `membersCount` | int            | Number of group members                                                  |
  | `tags`         | Array\<String> | List of tags for group identification                                    |
  | `hasJoined`    | boolean        | Whether logged-in user has joined                                        |
  | `scope`        | String         | User's scope in group. Values: `"admin"`, `"moderator"`, `"participant"` |
</Accordion>

<Accordion title="ReactionCount Object">
  The nested `ReactionCount` object (used in `reactions` array) contains:

  | Parameter     | Type    | Description                                            |
  | ------------- | ------- | ------------------------------------------------------ |
  | `reaction`    | String  | The reaction emoji                                     |
  | `count`       | int     | Total count of this reaction                           |
  | `reactedByMe` | boolean | Whether the logged-in user has reacted with this emoji |
</Accordion>
