> ## 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.

# Send Messages

> Send text, media, and custom messages to users and groups using the CometChat Android SDK.

<Accordion title="AI Integration Quick Reference">
  ```kotlin theme={null}
  // Text message
  val textMessage = TextMessage("UID", "Hello!", CometChatConstants.RECEIVER_TYPE_USER)
  CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(msg: TextMessage) { }
      override fun onError(e: CometChatException) { }
  })

  // Media message (file upload)
  val mediaMessage = MediaMessage("UID", File("/path/to/file.jpg"),
      CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)
  CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(msg: MediaMessage) { }
      override fun onError(e: CometChatException) { }
  })

  // Custom message
  val customData = JSONObject().apply { put("latitude", "19.07"); put("longitude", "72.87") }
  val customMessage = CustomMessage("UID", CometChatConstants.RECEIVER_TYPE_USER, "LOCATION", customData)
  CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(msg: CustomMessage) { }
      override fun onError(e: CometChatException) { }
  })
  ```

  | Type   | Method                | Receiver Types                              |
  | ------ | --------------------- | ------------------------------------------- |
  | Text   | `sendMessage()`       | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
  | Media  | `sendMediaMessage()`  | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
  | Custom | `sendCustomMessage()` | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
</Accordion>

CometChat supports three types of messages:

| Type                      | Method                | Use Case                          |
| ------------------------- | --------------------- | --------------------------------- |
| [Text](#text-message)     | `sendMessage()`       | Plain text messages               |
| [Media](#media-message)   | `sendMediaMessage()`  | Images, videos, audio, files      |
| [Custom](#custom-message) | `sendCustomMessage()` | Location, polls, or any JSON data |

You can also send [Interactive Messages](/sdk/android/interactive-messages) for forms, cards, and custom UI elements.

## Text Message

Send a text message using `sendMessage()` with a [`TextMessage`](/sdk/reference/messages#textmessage) object.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String receiverID = "UID";
    private String messageText = "Hello CometChat!";
    private String receiverType = CometChatConstants.RECEIVER_TYPE_USER;

    TextMessage textMessage = new TextMessage(receiverID, messageText, receiverType);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
      @Override
      public void onSuccess(TextMessage textMessage) {
          Log.d(TAG, "Message sent successfully: " + textMessage.toString());
      }

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

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val receiverID = "UID"
    private val messageText = "Hello CometChat!"
    private val receiverType = CometChatConstants.RECEIVER_TYPE_USER

    val textMessage = TextMessage(receiverID, messageText, receiverType)

    CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(textMessage: TextMessage) {
          Log.d(TAG, "Message sent successfully: $textMessage")
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    private String receiverID = "GUID";
    private String messageText = "Hello CometChat!";
    private String receiverType = CometChatConstants.RECEIVER_TYPE_GROUP;

    TextMessage textMessage = new TextMessage(receiverID, messageText, receiverType);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
      @Override
      public void onSuccess(TextMessage textMessage) {
          Log.d(TAG, "Message sent successfully: " + textMessage.toString());
      }

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

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val receiverID = "GUID"
    private val messageText = "Hello CometChat!"
    private val receiverType = CometChatConstants.RECEIVER_TYPE_GROUP

    val textMessage = TextMessage(receiverID, messageText, receiverType)
    CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(textMessage: TextMessage) {
          Log.d(TAG, "Message sent successfully: $textMessage")
      }

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

The `TextMessage` class constructor takes the following parameters:

| Parameter      | Description                                                      | Required |
| -------------- | ---------------------------------------------------------------- | -------- |
| `receiverID`   | `UID` of the user or `GUID` of the group receiving the message   | Yes      |
| `messageText`  | The text message content                                         | Yes      |
| `receiverType` | `CometChatConstants.RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP` | Yes      |

On success, `sendMessage()` returns a [`TextMessage`](/sdk/reference/messages#textmessage) object containing all information about the sent message.

### Add Metadata

Attach custom JSON data to the message:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = new JSONObject();
    metadata.put("latitude", "50.6192171633316");
    metadata.put("longitude", "-72.68182268750002");
    textMessage.setMetadata(metadata);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = JSONObject()
    metadata.put("latitude", "50.6192171633316")
    metadata.put("longitude", "-72.68182268750002")
    textMessage.setMetadata(metadata)
    ```
  </Tab>
</Tabs>

### Add Tags

Tag messages for easy filtering later:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    textMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    textMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

### Quote a Message

Reply to a specific message by setting its ID:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    textMessage.setQuotedMessageId(10);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    textMessage.quotedMessageId = 10
    ```
  </Tab>
</Tabs>

## Media Message

Send images, videos, audio, or files using `sendMediaMessage()`.

There are two ways to send media messages:

1. **Upload a file** — Pass a `File` object and CometChat uploads it automatically
2. **Send a URL** — Provide a URL to media hosted on your server or cloud storage

### Add Metadata

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = new JSONObject();
    metadata.put("latitude", "50.6192171633316");
    metadata.put("longitude", "-72.68182268750002");
    mediaMessage.setMetadata(metadata);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = JSONObject()
    metadata.put("latitude", "50.6192171633316")
    metadata.put("longitude", "-72.68182268750002")
    mediaMessage.setMetadata(metadata)
    ```
  </Tab>
</Tabs>

### Add Caption

Add text along with the media:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    mediaMessage.setCaption("Message Caption");
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    mediaMessage.setCaption("Message Caption")
    ```
  </Tab>
</Tabs>

### Add Tags

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    mediaMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    mediaMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

### Upload a File

Pass a `File` object directly. CometChat uploads it to its servers and returns the URL in the success response.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String receiverID = "UID";
    private String messageType = CometChatConstants.MESSAGE_TYPE_IMAGE;
    private String receiverType = CometChatConstants.RECEIVER_TYPE_USER;
    private String filePath = "/storage/emulated/0/Download/CometChat.jpg";

    MediaMessage mediaMessage = new MediaMessage(receiverID, new File(filePath), messageType, receiverType);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString());
      }

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

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val receiverID = "UID"
    private val messageType = CometChatConstants.MESSAGE_TYPE_IMAGE
    private val receiverType = CometChatConstants.RECEIVER_TYPE_USER
    private val filePath = "/storage/emulated/0/Download/CometChat.jpg"

    val mediaMessage = MediaMessage(receiverID, File(filePath), messageType, receiverType)
    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(mediaMessage: MediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString())
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    private String receiverID = "GUID";
    private String messageType = CometChatConstants.MESSAGE_TYPE_IMAGE;
    private String receiverType = CometChatConstants.RECEIVER_TYPE_GROUP;
    private String filePath = "/storage/emulated/0/Download/CometChat.jpg";

    MediaMessage mediaMessage = new MediaMessage(receiverID, new File(filePath), messageType, receiverType);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString());
      }

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

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val receiverID = "GUID"
    private val messageType = CometChatConstants.MESSAGE_TYPE_IMAGE
    private val receiverType = CometChatConstants.RECEIVER_TYPE_GROUP
    private val filePath = "/storage/emulated/0/Download/CometChat.jpg"

    val mediaMessage = MediaMessage(receiverID, File(filePath), messageType, receiverType)
    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(mediaMessage: MediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString())
      }

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

The `MediaMessage` class constructor takes the following parameters:

| Parameter      | Description                                                                              | Required |
| -------------- | ---------------------------------------------------------------------------------------- | -------- |
| `receiverId`   | The UID or GUID of the recipient                                                         | Yes      |
| `file`         | The `File` object to upload                                                              | Yes      |
| `messageType`  | `MESSAGE_TYPE_IMAGE`, `MESSAGE_TYPE_VIDEO`, `MESSAGE_TYPE_AUDIO`, or `MESSAGE_TYPE_FILE` | Yes      |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP`                                            | Yes      |

### Send a URL

Send media hosted on your server or cloud storage using the [`Attachment`](/sdk/reference/auxiliary#attachment) class:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "recipient_UID";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER);

    Attachment attachment = new Attachment();
    attachment.setFileName("test");
    attachment.setFileExtension("png");
    attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");

    mediaMessage.setAttachment(attachment);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage1) {
          Log.i(TAG, "onSuccess");
      }

      @Override
      public void onError(CometChatException e) {
          Log.e(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "recipient_UID"

    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)

    val attachment = Attachment()
    attachment.fileName = "test"
    attachment.fileExtension = "png"
    attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"

    mediaMessage.attachment = attachment

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage1: MediaMessage?) {
          Log.i(TAG, "onSuccess")
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    String receiverId = "recipient_GUID";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP);

    Attachment attachment = new Attachment();
    attachment.setFileName("test");
    attachment.setFileExtension("png");
    attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");

    mediaMessage.setAttachment(attachment);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage1) {
          Log.i(TAG, "onSuccess");
      }

      @Override
      public void onError(CometChatException e) {
          Log.e(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val receiverId = "recipient_GUID"

    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP)

    val attachment = Attachment()
    attachment.fileName = "test"
    attachment.fileExtension = "png"
    attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"

    mediaMessage.attachment = attachment

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage1: MediaMessage?) {
          Log.i(TAG, "onSuccess")
      }

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

On success, `sendMediaMessage()` returns a [`MediaMessage`](/sdk/reference/messages#mediamessage) object.

## Multiple Attachments

Starting version 3.0.9, the SDK supports sending multiple attachments in a single media message.

### Upload Multiple Files

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "cometchat-uid-1";

    List<File> files = new ArrayList<File>();
    files.add(new File("/storage/emulated/0/Download/1.jpg"));
    files.add(new File("/storage/emulated/0/Download/2.jpg"));
    files.add(new File("/storage/emulated/0/Download/3.jpg"));

    MediaMessage mediaMessage = new MediaMessage(receiverId, files, fileType, CometChatConstants.RECEIVER_TYPE_USER);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Message Sent Successfully")
      }

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

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "cometchat-uid-1"
    val files: MutableList<File> = ArrayList()
    files.add(File("/storage/emulated/0/Download/1.jpg"))
    files.add(File("/storage/emulated/0/Download/2.jpg"))
    files.add(File("/storage/emulated/0/Download/3.jpg"))

    val mediaMessage = MediaMessage(receiverId, files, fileType, CometChatConstants.RECEIVER_TYPE_USER)

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage: MediaMessage?) {
          Log.d(TAG, "Message Sent Successfully")
      }

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

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

    List<File> files = new ArrayList<File>();
    files.add(new File("/storage/emulated/0/Download/1.jpg"));
    files.add(new File("/storage/emulated/0/Download/2.jpg"));
    files.add(new File("/storage/emulated/0/Download/3.jpg"));

    MediaMessage mediaMessage = new MediaMessage(groupId, files, fileType, CometChatConstants.RECEIVER_TYPE_GROUP);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Message Sent Successfully")
      }

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

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val groupId = "cometchat-guid-1"

    val files: MutableList<File> = ArrayList()
    files.add(File("/storage/emulated/0/Download/1.jpg"))
    files.add(File("/storage/emulated/0/Download/2.jpg"))
    files.add(File("/storage/emulated/0/Download/3.jpg"))

    val mediaMessage = MediaMessage(groupId, files, fileType, CometChatConstants.RECEIVER_TYPE_GROUP)

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage: MediaMessage?) {
          Log.d(TAG, "Message Sent Successfully")
      }

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

The `MediaMessage` class constructor takes the following parameters:

| Parameter      | Description                                                                              | Required |
| -------------- | ---------------------------------------------------------------------------------------- | -------- |
| `receiverId`   | The `UID` or `GUID` of the recipient                                                     | Yes      |
| `files`        | A `List<File>` of files to upload                                                        | Yes      |
| `messageType`  | `MESSAGE_TYPE_IMAGE`, `MESSAGE_TYPE_VIDEO`, `MESSAGE_TYPE_AUDIO`, or `MESSAGE_TYPE_FILE` | Yes      |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP`                                            | Yes      |

### Send Multiple URLs

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "cometchat-uid-1";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER);

    List<Attachment> attachments = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Attachment attachment = new Attachment();
        attachment.setFileName("test");
        attachment.setFileExtension("png");
        attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");
        attachment.setFileMimeType("image/png");
        attachments.add(attachment);
    }

    mediaMessage.setAttachments(attachments);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
        @Override
        public void onSuccess(MediaMessage mediaMessage) {
            Log.d(TAG, "Message Sent Successfully")
        }

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

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "cometchat-uid-1"
    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)

    val attachments: MutableList<Attachment> = ArrayList()
    for (i in 0..4) {
        val attachment = Attachment()
        attachment.fileName = "test"
        attachment.fileExtension = "png"
        attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"
        attachment.fileMimeType = "image/png"
        attachments.add(attachment)
    }

    mediaMessage.attachments = attachments

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
        override fun onSuccess(mediaMessage: MediaMessage?) {
            Log.d(TAG, "Message Sent Successfully")
        }

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

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

    MediaMessage mediaMessage = new MediaMessage(groupId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP);

    List<Attachment> attachments = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Attachment attachment = new Attachment();
        attachment.setFileName("test");
        attachment.setFileExtension("png");
        attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");
        attachment.setFileMimeType("image/png");
        attachments.add(attachment);
    }

    mediaMessage.setAttachments(attachments);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
        @Override
        public void onSuccess(MediaMessage mediaMessage) {
            Log.d(TAG, "Message Sent Successfully")
        }

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

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val groupId = "cometchat-guid-1"
    val mediaMessage = MediaMessage(groupId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP)

    val attachments: MutableList<Attachment> = ArrayList()
    for (i in 0..4) {
        val attachment = Attachment()
        attachment.fileName = "test"
        attachment.fileExtension = "png"
        attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"
        attachment.fileMimeType = "image/png"
        attachments.add(attachment)
    }

    mediaMessage.attachments = attachments

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
        override fun onSuccess(mediaMessage: MediaMessage?) {
            Log.d(TAG, "Message Sent Successfully")
        }

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

When a media message is sent successfully, the response will include a [`MediaMessage`](/sdk/reference/messages#mediamessage) object which includes all information related to the sent message.

You can use the `setMetadata()`, `setCaption()` & `setTags()` methods to add metadata, caption and tags in the same way as a single attachment.

## Custom Message

Send custom data that doesn't fit text or media using `sendCustomMessage()`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CustomMessage customMessage = new CustomMessage(receiverId, receiverType, customType, customData)
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val customMessage = CustomMessage(receiverId, receiverType, customType, customData)
    ```
  </Tab>
</Tabs>

| Parameter      | Description                                                  | Required |
| -------------- | ------------------------------------------------------------ | -------- |
| `receiverId`   | UID of the user or GUID of the group                         | Yes      |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP`                | Yes      |
| `customType`   | Developer-defined type string (e.g., `"LOCATION"`, `"POLL"`) | Yes      |
| `customData`   | The payload as a `JSONObject`                                | Yes      |

You can also set a subtype using `setSubtype()` to further classify the custom message.

### Add Tags

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    customMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    customMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

Once the message object is ready, call `sendCustomMessage()`.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")
    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")
    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

On success, `sendCustomMessage()` returns a [`CustomMessage`](/sdk/reference/messages#custommessage) object.

### Control Conversation Update

By default, a custom message updates the conversation's last message. To prevent this:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);
    customMessage.shouldUpdateConversation(false);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)
    customMessage.shouldUpdateConversation(false)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);
    customMessage.shouldUpdateConversation(false);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)
    customMessage.shouldUpdateConversation(false)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

### Custom Notification Text

Set custom text for push, email, and SMS notifications:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);
    customMessage.setConversationText("Custom Notification Body");

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)
    customMessage.setConversationText("Custom Notification Body")

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);
    customMessage.setConversationText("Custom Notification Body");

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)
    customMessage.setConversationText("Custom Notification Body")

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

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

<Note>
  It is also possible to send interactive messages from CometChat, to know more [click here](/sdk/android/interactive-messages)
</Note>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Receive Messages" icon="envelope" href="/sdk/android/receive-messages">
    Listen for incoming messages in real time
  </Card>

  <Card title="Edit Message" icon="pen" href="/sdk/android/edit-message">
    Modify sent messages after delivery
  </Card>

  <Card title="Delete Message" icon="trash" href="/sdk/android/delete-message">
    Remove messages from conversations
  </Card>

  <Card title="Interactive Messages" icon="square-check" href="/sdk/android/interactive-messages">
    Send messages with embedded forms and buttons
  </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>
