> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ably/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Messages

Send, update, delete, and receive messages in a chat room with any number of participants. Users subscribe to messages by registering a listener, and send messages to all users that are subscribed to receive them.

## Subscribe to Messages

<Tabs>
  <Tab name="JavaScript">
    <Code>
      ```javascript theme={null}
      const {unsubscribe} = room.messages.subscribe((event) => {
        console.log(event.message);
      });
      ```
    </Code>
  </Tab>

  <Tab name="React">
    <Code>
      ```react theme={null}
      import { useState } from 'react';
      import { useMessages } from '@ably/chat/react';

      const MyComponent = () => {
        useMessages({
          listener: (event) => {
            console.log('Received message: ', event.message);
          },
        });

        return <div>...</div>;
      };
      ```
    </Code>
  </Tab>

  <Tab name="Swift">
    <Code>
      ```swift theme={null}
      let messagesSubscription = try await room.messages.subscribe()
      for await message in messagesSubscription {
          print("Message received: \(message)")
      }
      ```
    </Code>
  </Tab>

  <Tab name="Android / Kotlin">
    <Code>
      ```android theme={null}
      import com.ably.chat.Room
      import com.ably.chat.asFlow

      @Composable
      fun SimpleMessagesComponent(room: Room) {
        LaunchedEffect(room) {
          room.messages.asFlow().collect { event ->
            println("Received message: ${event.message}")
          }
        }
      }
      ```
    </Code>
  </Tab>
</Tabs>

### Message Structure

The following is the structure of a message:

<Code>
  ```json theme={null}
  {
    "serial": "01826232498871-001@abcdefghij:001",
    "clientId": "basketLover014",
    "text": "What a shot!",
    "headers": {},
    "metadata": {},
    "timestamp": "2024-06-12T11:37:59.988Z",
    "action": "message.create"
  }
  ```
</Code>

The following are the properties of a message:

| Property    | Description                                                      | Type     |
| ----------- | ---------------------------------------------------------------- | -------- |
| `serial`    | An Ably-generated ID used to uniquely identify the message.      | `String` |
| `clientId`  | The client identifier of the user that created the message.      | `String` |
| `text`      | The message contents.                                            | `String` |
| `headers`   | Optional headers for adding additional information to a message. | `Object` |
| `metadata`  | Optional additional metadata about the message.                  | `Object` |
| `timestamp` | The time the message was created.                                | `Date`   |
| `action`    | The latest action performed on this message.                     | `String` |

## Send a Message

<Tabs>
  <Tab name="JavaScript">
    <Code>
      ```javascript theme={null}
      await room.messages.send({text: 'hello'});
      ```
    </Code>
  </Tab>

  <Tab name="React">
    <Code>
      ```react theme={null}
      import { useMessages } from '@ably/chat/react';

      const MyComponent = () => {
        const { sendMessage } = useMessages();

        const handleMessageSend = () => {
          sendMessage({ text: 'Hello, World!' });
        };

        return (
          <div>
            <button onClick={handleMessageSend}>Send Message</button>
          </div>
        );
      };
      ```
    </Code>
  </Tab>

  <Tab name="Swift">
    <Code>
      ```swift theme={null}
      let message = try await room.messages.send(withParams: .init(text: "hello"))
      ```
    </Code>
  </Tab>

  <Tab name="Android / Kotlin">
    <Code>
      ```android theme={null}
      import com.ably.chat.Room
      import kotlinx.coroutines.launch

      @Composable
      fun MyComponent(room: Room) {
        val coroutineScope = rememberCoroutineScope()

        Button(onClick = {
          coroutineScope.launch {
            room.messages.send(text = "hello")
          }
        }) {
          Text("Send Message")
        }
      }
      ```
    </Code>
  </Tab>
</Tabs>

## Update a Message

<Tabs>
  <Tab name="JavaScript">
    <Code>
      ```javascript theme={null}
      import { Message } from '@ably/chat';
      const message: Message
      const updatedMessage = message.copy({text: "my updated text"})
      await room.messages.update(updatedMessage.serial, updatedMessage, { description: "Message update by user" });
      ```
    </Code>
  </Tab>

  <Tab name="React">
    <Code>
      ```react theme={null}
      import { Message } from '@ably/chat';
      import { useMessages } from '@ably/chat/react';

      const MyComponent = () => {
        const { updateMessage } = useMessages();
        const [message, setMessage] = useState<Message>();

        const handleMessageUpdate = (msg: Message) => {
          updateMessage(msg.serial, msg.copy({ text: "my updated text" }), { description: "Message update by user" })
          .then((updatedMsg: Message) => {
            console.log('Message updated:', updatedMsg);
          })
          .catch((error) => {
            console.error('Error updating message: ', error);
          });
        };
        return (
          <div>
            <button onClick={() => handleMessageUpdate(message)}>Update Message</button>
          </div>
        );
      };
      ```
    </Code>
  </Tab>

  <Tab name="Swift">
    <Code>
      ```swift theme={null}
      let originalMessage: Message
      let updatedMessage = try await room.messages.update(
        withSerial: originalMessage.serial,
        params: .init(text: "my updated text"),
        details: .init(description: "Message update by user")
      )
      ```
    </Code>
  </Tab>

  <Tab name="Android / Kotlin">
    <Code>
      ```android theme={null}
      import com.ably.chat.Message
      import com.ably.chat.Room
      import com.ably.chat.copy
      import com.ably.chat.update

      @Composable
      fun MyComponent(room: Room) {
        val coroutineScope = rememberCoroutineScope()
        val originalMessage: Message

        Button(onClick = {
          coroutineScope.launch {
            room.messages.update(
              originalMessage.copy(text = "my updated text"),
              operationDescription = "Message update by user",
            )
          }
        }) {
          Text("Update Message")
        }
      }
      ```
    </Code>
  </Tab>
</Tabs>

## Delete a Message

<Tabs>
  <Tab name="JavaScript">
    <Code>
      ```javascript theme={null}
      import { Message } from '@ably/chat';
      const messageToDelete: Message
      await room.messages.delete(messageToDelete.serial, { description: 'Message deleted by user' });
      ```
    </Code>
  </Tab>

  <Tab name="React">
    <Code>
      ```react theme={null}
      import { Message } from '@ably/chat';
      import { useMessages } from '@ably/chat/react';

      const MyComponent = () => {
        const { deleteMessage } = useMessages();
        const [message, setMessage] = useState<Message>();

        const handleMessageDelete = (msg: Message) => {
          deleteMessage(msg.serial, { description: 'Message deleted by user' })
          .then((deletedMessage: Message) => {
            console.log('Message deleted:', deletedMessage);
          })
          .catch((error) => {
            console.error('Error deleting message: ', error);
          });
        };

        return (
          <div>
            <button onClick={() => handleMessageDelete(message)}>Delete Message</button>
          </div>
        );
      };
      ```
    </Code>
  </Tab>

  <Tab name="Swift">
    <Code>
      ```swift theme={null}
      let messageToDelete: Message
      let deletedMessage = try await room.messages.delete(
        withSerial: messageToDelete.serial,
        details: .init(description: "Message deleted by user")
      )
      ```
    </Code>
  </Tab>

  <Tab name="Android / Kotlin">
    <Code>
      ```android theme={null}
      import com.ably.chat.Message
      import com.ably.chat.Room
      import com.ably.chat.delete

      @Composable
      fun MyComponent(room: Room) {
        val coroutineScope = rememberCoroutineScope()
        val messageToDelete: Message

        Button(onClick = {
          coroutineScope.launch {
            room.messages.delete(
              messageToDelete,
              operationDescription = "Message deleted by user",
            )
          }
        }) {
          Text("Delete Message")
        }
      }
      ```
    </Code>
  </Tab>
</Tabs>

## Next Steps

* Learn about [presence](/docs/chat/rooms/presence)
* Explore [typing indicators](/docs/chat/rooms/typing-indicators)
* Understand [room reactions](/docs/chat/rooms/reactions)
