> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-llms-scoped-indexes.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>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.