# Message Read Indicators

Read indicators show the sender when their messages have been seen by other channel members. This page covers **message delivery states** — the per-message sending status icon shown in the footer of the sender's messages — and how to access the underlying read and delivery state programmatically.

### Message delivery states

`StreamMessageSendingStatus` is rendered in the footer of every outgoing message (messages sent by the current user). It displays one of four states:

| State         | Icon                      | When                                                              |
| ------------- | ------------------------- | ----------------------------------------------------------------- |
| **Sending**   | Clock                     | Message is in flight (or attachments are still uploading)         |
| **Sent**      | Single checkmark          | Message reached the server but has not been delivered to any peer |
| **Delivered** | Double checkmark (grey)   | Message delivered to at least one other member's device           |
| **Read**      | Double checkmark (accent) | At least one other member has read up to this message             |

No configuration is required — the status updates automatically as events arrive from the Stream backend. The widget is only shown for the current user's own messages; incoming messages from others never display a delivery status.

![](@chat-sdk/flutter/v10-latest/_assets/message_delivery_states.png)

If attachments are still uploading, a progress text (e.g. "Uploading 1/3…") is shown in place of the checkmark icon until the upload completes.

### Enabling or disabling read events

Read events must be enabled at the channel level for read indicators to function. They are enabled by default on most channel types. Confirm this in your Stream Dashboard under channel type settings.

### Marking messages as read

`StreamMessageListView` automatically marks the channel as read once the user scrolls to the bottom of the list (controlled by `markReadWhenAtTheBottom`, default `true`). To mark messages as read manually (for example, when the app returns to the foreground), call:

```dart
await channel.markRead();
```

### Reading the channel read and delivery state

The full read and delivery state for all channel members is available on `channel.state?.read`, which returns a `List<Read>`. Each `Read` object covers both concepts:

| Field                    | Description                                                                                           |
| ------------------------ | ----------------------------------------------------------------------------------------------------- |
| `user`                   | The channel member this entry belongs to                                                              |
| `lastRead`               | Timestamp of the most recent read event for this member                                               |
| `lastReadMessageId`      | ID of the last message this member has read                                                           |
| `lastDeliveredAt`        | Timestamp of the most recent delivery confirmation (may be `null` if delivery events are not enabled) |
| `lastDeliveredMessageId` | ID of the last message delivered to this member's device                                              |
| `unreadMessages`         | Number of unread messages for this member                                                             |

```dart
final channel = StreamChannel.of(context).channel;
final reads = channel.state?.read; // List<Read>
```

To query the state for a specific message, use the extension methods on `List<Read>`:

```dart
// Members who have read up to (and including) a given message
final readers = reads?.readsOf(message: message) ?? [];

// Members who have received (delivered) a given message but may not have read it yet
final delivered = reads?.deliveriesOf(message: message) ?? [];
```

`readsOf` returns members whose `lastRead` is on or after the message's `createdAt` (excluding the sender). `deliveriesOf` returns members whose `lastDeliveredAt` is on or after the message's `createdAt`, or who have already read it.

To react to changes in real time, subscribe to the stream instead:

```dart
channel.state?.readStream.listen((reads) {
  // called whenever any member's read or delivery state changes
});
```


---

This page was last updated at 2026-06-09T15:44:03.776Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/flutter/stream-chat-flutter/message-list/read-indicators/](https://getstream.io/chat/docs/sdk/flutter/stream-chat-flutter/message-list/read-indicators/).