Skip to main content

Read receipts

Read receipts track the read status of individual messages in direct channels and group channels.

Send a message with read receipt

Set needReceipt = true on the message before sending.

kotlin
val channel = DirectChannel("userId")

val params = SendMessageParams(content = TextMessage("This message requires a read receipt")).apply {
needReceipt = true
}

channel.sendMessage(params, object : SendMessageHandler {
override fun onAttached(message: Message) {}
override fun onResult(message: Message, error: NCError?) {
if (error == null) {
Log.d("Receipt", "Message sent, awaiting read receipt")
} else {
Log.e("Receipt", "Send failed: ${error.message}")
}
}
})

Send a read receipt

After reading a message, the recipient sends a read receipt back to the sender.

kotlin
val channel = DirectChannel("userId")

NCEngine.addMessageHandler("myHandler", object : MessageHandler {
override fun onMessageReceived(message: Message, left: Int, hasPackage: Boolean, offline: Boolean) {
if (message.needReceipt && !message.sentReceipt) {
channel.sendReadReceiptResponse(listOf(message.messageId)) { error ->
if (error == null) {
Log.d("Receipt", "Read receipt sent")
message.sentReceipt = true
}
}
}
}
})

Listen for read receipts

The message sender can listen for incoming read receipts.

kotlin
NCEngine.addMessageHandler("myHandler", object : MessageHandler {
override fun onMessageReceiptResponse(event: MessageReceiptResponseEvent) {
event.responses.forEach { response ->
Log.d("Receipt", "Message ${response.messageId} read count: ${response.readCount}")
updateMessageReadStatus(response)
}
}
})

Query read receipt info

Actively query the read receipt status of specific messages.

kotlin
val channel = DirectChannel("userId")
val messageIds = listOf(message1.messageId, message2.messageId)

channel.getReadReceiptInfo(messageIds) { receiptInfoList, error ->
if (error == null && receiptInfoList != null) {
receiptInfoList.forEach { info ->
Log.d("Receipt", "Message ${info.messageId}: read=${info.readCount}, unread=${info.unreadCount}")
}
}
}

Query read/unread users

In group channels, query which users have read or not read a specific message.

kotlin
val channel = DirectChannel("userId")

val params = MessagesReadReceiptUsersQueryParams(
channelIdentifier = channel.channelIdentifier,
messageId = message.messageId ?: ""
).apply {
pageSize = 20
status = MessageReadReceiptStatus.RESPONDED
}

val query = BaseChannel.createMessagesReadReceiptUsersQuery(params)

query.loadNextPage { result, error ->
if (error == null && result != null) {
result.data.forEach { user ->
Log.d("Receipt", "${user.userId} - ${user.readTime}")
}
}
}

Parameters

Message properties

PropertyTypeDescription
needReceiptBooleanWhether the message supports read receipts. Set before sending.
sentReceiptBooleanWhether the read receipt has been sent (recipient side).

sendReadReceiptResponse

ParameterTypeDescription
messageIdsList<String>The UIDs of the read messages.
handlerErrorHandlerThe completion callback.

ReadReceiptInfo

PropertyTypeDescription
messageIdStringThe message's unique identifier.
readCountIntNumber of users who have read the message.
unreadCountIntNumber of users who have not read the message.

Important notes

  • Only messages with needReceipt = true support read receipts.
  • Use messageId for read receipt operations.
  • Recipients must explicitly call sendReadReceiptResponse() to send read receipts.
  • In group channels, you can query the read/unread user list.