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
- Java
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}")
}
}
})
Java
DirectChannel channel = new DirectChannel("userId");
SendMessageParams params = new SendMessageParams(new TextMessage("This message requires a read receipt"));
params.setNeedReceipt(true);
channel.sendMessage(params, new SendMessageHandler() {
@Override
public void onAttached(@NonNull Message message) {}
@Override
public void onResult(@NonNull Message message, @Nullable NCError error) {
if (error == null) {
Log.d("Receipt", "Message sent, awaiting read receipt");
} else {
Log.e("Receipt", "Send failed: " + error.getMessage());
}
}
});
Send a read receipt
After reading a message, the recipient sends a read receipt back to the sender.
- Kotlin
- Java
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
}
}
}
}
})
Java
DirectChannel channel = new DirectChannel("userId");
NCEngine.addMessageHandler("myHandler", new MessageHandler() {
@Override
public void onMessageReceived(Message message, int left, boolean hasPackage, boolean offline) {
if (message.isNeedReceipt() && !message.isSentReceipt()) {
List<String> messageIds = Collections.singletonList(message.getMessageId());
channel.sendReadReceiptResponse(messageIds, new ErrorHandler() {
@Override
public void onResult(NCError error) {
if (error == null) {
Log.d("Receipt", "Read receipt sent");
message.setSentReceipt(true);
}
}
});
}
}
});
Listen for read receipts
The message sender can listen for incoming read receipts.
- Kotlin
- Java
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)
}
}
})
Java
NCEngine.addMessageHandler("myHandler", new MessageHandler() {
@Override
public void onMessageReceiptResponse(@NonNull MessageReceiptResponseEvent event) {
for (MessageReceiptResponse response : event.getResponses()) {
Log.d("Receipt", "Message " + response.getMessageId() +
" read count: " + response.getReadCount());
updateMessageReadStatus(response);
}
}
});
Query read receipt info
Actively query the read receipt status of specific messages.
- Kotlin
- Java
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}")
}
}
}
Java
DirectChannel channel = new DirectChannel("userId");
List<String> messageIds = Arrays.asList(message1.getMessageId(), message2.getMessageId());
channel.getReadReceiptInfo(messageIds, (receiptInfoList, error) -> {
if (error == null && receiptInfoList != null) {
for (ReadReceiptInfo info : receiptInfoList) {
Log.d("Receipt", "Message " + info.getMessageId() + ": read=" + info.getReadCount() + ", unread=" + info.getUnreadCount());
}
}
});
Query read/unread users
In group channels, query which users have read or not read a specific message.
- Kotlin
- Java
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}")
}
}
}
Java
DirectChannel channel = new DirectChannel("userId");
MessagesReadReceiptUsersQueryParams params = new MessagesReadReceiptUsersQueryParams(
channel.getChannelIdentifier(), message.getMessageId()
);
params.setPageSize(20);
params.setStatus(MessageReadReceiptStatus.RESPONDED);
MessagesReadReceiptUsersQuery query = BaseChannel.createMessagesReadReceiptUsersQuery(params);
query.loadNextPage((result, error) -> {
if (error == null && result != null) {
for (ReadReceiptUser user : result.getData()) {
Log.d("Receipt", user.getUserId() + " - " + user.getReadTime());
}
}
});
Parameters
Message properties
| Property | Type | Description |
|---|---|---|
needReceipt | Boolean | Whether the message supports read receipts. Set before sending. |
sentReceipt | Boolean | Whether the read receipt has been sent (recipient side). |
sendReadReceiptResponse
| Parameter | Type | Description |
|---|---|---|
messageIds | List<String> | The UIDs of the read messages. |
handler | ErrorHandler | The completion callback. |
ReadReceiptInfo
| Property | Type | Description |
|---|---|---|
messageId | String | The message's unique identifier. |
readCount | Int | Number of users who have read the message. |
unreadCount | Int | Number of users who have not read the message. |
Important notes
- Only messages with
needReceipt = truesupport read receipts. - Use
messageIdfor read receipt operations. - Recipients must explicitly call
sendReadReceiptResponse()to send read receipts. - In group channels, you can query the read/unread user list.