# Delivered & Read Status

Messages go through multiple states reflecting recipient interaction:

- **Sent** - The message reached the Stream server. Confirmed via the `message.new` WebSocket event.
- **Delivered** - The recipient's device confirmed delivery. Confirmed via the `message.delivered` WebSocket event. Disabled by default.
- **Read** - The recipient marked the channel as read. Confirmed via the `message.read` WebSocket event.

For marking channels as read/unread and retrieving unread counts, see [Unread Counts](https://getstream.io/chat/docs/flutter-dart/unread/).

## Delivery Receipts

Delivery receipts track when messages are delivered to recipient devices.

<Admonition type="info">

Contact support to enable message delivery tracking for your app.

</Admonition>

<Admonition type="warning">

The Android SDK requires the [offline plugin](https://getstream.io/chat/docs/sdk/android/basics/offline-support/) for delivery receipts to function correctly.

</Admonition>

### Enabling Delivery Receipts

#### Channel Type Configuration

Enable delivery tracking for all channels of a type.

```js label="Node.js"
// When creating a channel type
await client.createChannelType("targetChannelType", { delivery_events: true });

// When updating an existing channel type
await client.updateChannelType("targetChannelType", { delivery_events: true });
```

You can also enable this in the Dashboard under channel type configuration.

#### User Privacy Settings

Control whether a user's delivery status is shared with others.

```dart label="Dart"
final currentUser = client.state.currentUser;
if (currentUser != null) {
  final settings = currentUser.privacySettings;
  await client.updateUser(currentUser.copyWith(
    privacySettings: PrivacySettings(
      typingIndicators: settings?.typingIndicators,
      readReceipts: settings?.readReceipts,
      deliveryReceipts: DeliveryReceipts(enabled: false),
    ),
  ));
}
```

When `privacy_settings.delivery_receipts.enabled` is `false`, the user's delivery status is not exposed to others, and the `message.delivered` event is not sent when this user confirms delivery.

<Admonition type="note">

In browser JavaScript, set privacy settings on the user object you pass to `connectUser` rather than calling `upsertUser`, which needs server auth. See [Privacy Settings](https://getstream.io/chat/docs/javascript/init-and-users/#privacy-settings).

</Admonition>

### Automatic Delivery Confirmation

The SDK automatically handles delivery confirmation, including request throttling and duplicate prevention.

<Admonition type="info">

Delivery tracking is currently supported for channel messages only, not thread replies.

</Admonition>

### Delivery Events

The `message.delivered` event is triggered when a message is delivered to a recipient's device. The event includes:

- `last_delivered_at` - Timestamp when messages were last confirmed as delivered
- `last_delivered_message_id` - ID of the last message confirmed as delivered

## Read Receipts

Read receipts track when users have read messages in a channel.

### Enabling Read Receipts

#### Channel Type Configuration

Enable read tracking for all channels of a type.

```js label="Node.js"
// When creating a channel type
await client.createChannelType("targetChannelType", { read_events: true });

// When updating an existing channel type
await client.updateChannelType("targetChannelType", { read_events: true });
```

You can also enable this in the Dashboard under channel type configuration.

#### User Privacy Settings

Control whether a user's read status is shared with others.

```dart label="Dart"
final currentUser = client.state.currentUser;
if (currentUser != null) {
  final settings = currentUser.privacySettings;
  await client.updateUser(currentUser.copyWith(
    privacySettings: PrivacySettings(
      typingIndicators: settings?.typingIndicators,
      deliveryReceipts: settings?.deliveryReceipts,
      readReceipts: ReadReceipts(enabled: false),
    ),
  ));
}
```

When `privacy_settings.read_receipts.enabled` is `false`, the user's read state is not exposed to others, and `message.read` and `notification.mark_read` events are not sent when this user reads messages.

### Read Events

The following events are triggered for read status:

- `message.read` - When any channel member marks the channel as read
- `notification.mark_read` - When the connected user marks a channel as read
- `notification.mark_unread` - When the connected user marks a message as unread

For handling these events and updating unread counts, see [Unread Counts](https://getstream.io/chat/docs/flutter-dart/unread/).

## Push Notification Delivery Confirmation

By default, when a push notification is received while the app is inactive, the message is not marked as delivered. To mark messages as delivered from push notifications, customize your push notification handling.

- [iOS Custom Push Notifications](https://getstream.io/chat/docs/sdk/ios/guides/push-notifications/#customising-remote-push-notifications)
- [Android Custom Push Notifications](https://getstream.io/chat/docs/sdk/android/guides/push-notifications/#customizing-push-notifications)

```kotlin label="Kotlin"
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
  context = context,
  notificationConfig = notificationConfig,
  onPushMessage = { pushMessage ->
    if (EventType.MESSAGE_NEW == pushMessage.type) {
      ChatClient.instance()
        .markMessageAsDelivered(messageId = pushMessage.messageId)
        .enqueue()
    }
    false // Return false to let the SDK show a notification
  },
)

ChatClient.Builder(apiKey, context)
  .notifications(notificationConfig, notificationHandler)
```


---

This page was last updated at 2026-08-13T00:26:26.059Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/flutter-dart/message-delivery-and-read-status/](https://getstream.io/chat/docs/flutter-dart/message-delivery-and-read-status/).