// 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 });Delivered & Read Status
Messages go through multiple states reflecting recipient interaction:
- Sent - The message reached the Stream server. Confirmed via the
message.newWebSocket event. - Delivered - The recipient’s device confirmed delivery. Confirmed via the
message.deliveredWebSocket event. Disabled by default. - Read - The recipient marked the channel as read. Confirmed via the
message.readWebSocket event.
For marking channels as read/unread and retrieving unread counts, see Unread Counts.
Delivery Receipts
Delivery receipts track when messages are delivered to recipient devices.
Contact support to enable message delivery tracking for your app.
The Android SDK requires the offline plugin for delivery receipts to function correctly.
Enabling Delivery Receipts
Channel Type Configuration
Enable delivery tracking for all channels of a type.
# When creating a channel type
client.create_channel_type({"name": "targetChannelType", "delivery_events": True})
# When updating an existing channel type
client.update_channel_type("targetChannelType", delivery_events=True)// When updating an existing channel type
client.UpdateChannelType(ctx, "targetChannelType", map[string]interface{}{
"delivery_events": true,
})await channelTypeClient.UpdateChannelTypeAsync("targetChannelType", new ChannelTypeWithStringCommandsRequest
{
DeliveryEvents = 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.
await client.upsertUser({
id: "user-id",
privacy_settings: {
delivery_receipts: {
enabled: false, // Do not report delivery status
},
},
});val chatClient = ChatClient.instance()
chatClient.getCurrentUser()?.let { currentUser ->
chatClient.updateUser(
user = currentUser.copy(
privacySettings = currentUser.privacySettings?.copy(
deliveryReceipts = DeliveryReceipts(enabled = false),
)
)
)
}let currentUserController = ChatClient.shared.currentUserController()
currentUserController.updateUserData(
privacySettings: .init(
deliveryReceipts: DeliveryReceiptsPrivacySettings(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.
Automatic Delivery Confirmation
The SDK automatically handles delivery confirmation, including request throttling and duplicate prevention.
Delivery tracking is currently supported for channel messages only, not thread replies.
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 deliveredlast_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.
// 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 });# When creating a channel type
client.create_channel_type({"name": "targetChannelType", "read_events": True})
# When updating an existing channel type
client.update_channel_type("targetChannelType", read_events=True)// When updating an existing channel type
client.UpdateChannelType(ctx, "targetChannelType", map[string]interface{}{
"read_events": true,
})await channelTypeClient.UpdateChannelTypeAsync("targetChannelType", new ChannelTypeWithStringCommandsRequest
{
ReadEvents = 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.
await client.upsertUser({
id: "user-id",
privacy_settings: {
read_receipts: {
enabled: false, // Do not report read status
},
},
});val chatClient = ChatClient.instance()
chatClient.getCurrentUser()?.let { currentUser ->
chatClient.updateUser(
user = currentUser.copy(
privacySettings = currentUser.privacySettings?.copy(
readReceipts = ReadReceipts(enabled = false),
)
)
)
}let currentUserController = ChatClient.shared.currentUserController()
currentUserController.updateUserData(
privacySettings: .init(
readReceipts: ReadReceiptsPrivacySettings(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 readnotification.mark_read- When the connected user marks a channel as readnotification.mark_unread- When the connected user marks a message as unread
For handling these events and updating unread counts, see Unread Counts.
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.
// In your NotificationService extension
let chatHandler = ChatRemoteNotificationHandler(client: client, content: content)
let chatNotification = chatHandler.handleNotification { chatContent in
switch chatContent {
case let .message(messageNotification):
switch messageNotification.type {
case .messageNew:
if let channel = messageNotification.channel {
chatHandler.markMessageAsDelivered(messageNotification.message, for: channel)
}
default:
break
}
}
}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)