await channel.markRead();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.

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:
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 |
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>:
// 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:
channel.state?.readStream.listen((reads) {
// called whenever any member's read or delivery state changes
});