# Message
The `Message` interface represents a single message in a chat room. Messages are received through the [`messages.subscribe()`](https://ably.com/docs/chat/api/javascript/messages.md#subscribe) method or retrieved via [`messages.history()`](https://ably.com/docs/chat/api/javascript/messages.md#history).
## Properties
The `Message` interface has the following properties:
| Property | Description | Type |
| --- | --- | --- |
| serial | The unique identifier of the message. | String |
| clientId | The client ID of the user who created the message. | String |
| text | The text content of the message. | String |
| timestamp | The timestamp at which the message was created. | Date |
| metadata | Extra information attached to the message for features like animations or linking to external resources. Always set; empty object if no metadata was provided. | |
| headers | Additional information in Ably realtime message extras, usable for features like livestream timestamping or message flagging. Always set; empty object if none provided. | |
| action | The action type indicating if the message was created, updated, or deleted. | |
| version | Information about the current version of this message. | |
| reactions | The reactions summary for this message. | |
| Value | Description |
| --- | --- |
| MessageCreate | The message was newly created. The value is `message.create`. |
| MessageUpdate | The message was updated. The value is `message.update`. |
| MessageDelete | The message was deleted. The value is `message.delete`. |
| Property | Required | Description | Type |
| --- | --- | --- | --- |
| serial | Required | The unique identifier for this version. | String |
| timestamp | Required | When this version was created. | Date |
| clientId | Optional | The client ID of the user who performed an update or deletion. | String or Undefined |
| description | Optional | A description of why this version was created. | String or Undefined |
| metadata | Optional | Additional metadata about the operation. | or Undefined |
| Property | Description | Type |
| --- | --- | --- |
| unique | Reactions counted with the "unique" strategy (one per client per message). Maps reaction name to summary. | |
| distinct | Reactions counted with the "distinct" strategy (one of each type per client). Maps reaction name to summary. | |
| multiple | Reactions counted with the "multiple" strategy (unlimited per client). Maps reaction name to summary. | |
| Property | Description | Type |
| --- | --- | --- |
| total | The total number of clients who have reacted with this name. | Number |
| clientIds | A list of the client IDs of all clients who have reacted with this name. | String[] |
| Property | Description | Type |
| --- | --- | --- |
| total | The total count of reactions with this name across all clients. | Number |
| clientIds | A map of client ID to the count each client has contributed. | `Record` |
| totalUnidentified | The total count from unidentified clients not included in `clientIds`. | Number |
## Apply an event to a message
`message.with(event: ChatMessageEvent | Message | MessageReactionSummaryEvent): Message`
Creates a new message instance with an event applied. This is useful for updating a local message state when receiving update or delete events. Returns the same instance if the event would be a no-op (e.g., applying an older version).
### Javascript
```
const updatedMessage = message.with(updateEvent);
```
### Parameters
The `with()` method takes the following parameters:
| Parameter | Required | Description | Type |
| --- | --- | --- | --- |
| event | Required | The event to apply to the message. | [Message](https://ably.com/docs/chat/api/javascript/message.md) or or |
| Property | Description | Type |
| --- | --- | --- |
| type | The type of the message event. | |
| message | The message that was received. | [Message](https://ably.com/docs/chat/api/javascript/message.md) |
| Value | Description |
| --- | --- |
| Created | A new chat message was received. The value is `message.created`. |
| Updated | A chat message was updated. The value is `message.updated`. |
| Deleted | A chat message was deleted. The value is `message.deleted`. |
| Property | Description | Type |
| --- | --- | --- |
| type | The event type. | |
| messageSerial | The serial of the message. | String |
| reactions | The aggregated reaction counts. | |
| Value | Description |
| --- | --- |
| Summary | A reaction summary update was received. The value is `reaction.summary`. |
### Returns
`Message`
Returns a new message instance with the event applied, or the same instance if the event would be a no-op.
## Copy a message
`message.copy(params?: MessageCopyParams): Message`
Creates a copy of the message with specified fields replaced.
### Javascript
```
const messageCopy = message.copy({ text: 'New text' });
```
### Parameters
The `copy()` method takes the following parameters:
| Parameter | Required | Description | Type |
| --- | --- | --- | --- |
| params | Optional | The fields to replace in the copy. | |
| Property | Required | Description | Type |
| --- | --- | --- | --- |
| text | Optional | The new text content. | String |
| metadata | Optional | The new metadata. | |
| headers | Optional | The new headers. | |
### Returns
`Message`
Returns a new message instance with the specified fields replaced.
## Example
### Javascript
```
import { ChatMessageAction } from '@ably/chat';
// Subscribe to messages and handle different actions
room.messages.subscribe((event) => {
const message = event.message;
console.log('Serial:', message.serial);
console.log('From:', message.clientId);
console.log('Text:', message.text);
console.log('Sent at:', message.timestamp);
console.log('Action:', message.action);
// Check if message has metadata
if (Object.keys(message.metadata).length > 0) {
console.log('Metadata:', message.metadata);
}
// Check message version for updates or deletions
if (message.action === ChatMessageAction.MessageUpdate) {
console.log('Updated by:', message.version.clientId);
console.log('Update reason:', message.version.description);
}
if (message.action === ChatMessageAction.MessageDelete) {
console.log('Deleted by:', message.version.clientId);
console.log('Delete reason:', message.version.description);
}
// Check reaction summary
for (const [name, summary] of Object.entries(message.reactions.distinct)) {
console.log(`${name}: ${summary.total} reactions from ${summary.clientIds.length} clients`);
}
});
```