---
source_url: https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/read-receipts
title: Read receipts
updated_at: 2026-06-15T12:11:34.017Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Read receipts

Read receipts show if channel members have viewed a message.

:::note Required setup
Read Receipts requires [Unread Message Count](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/unread). First, [set the last read timetoken](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/unread#mark-messages-as-read-one-channel) for each user on a channel.
:::

## Get read receipts

`onReadReceiptReceived()` provides real-time individual read receipt events on a channel. Each event contains a single user's read status as a typed `ReadReceipt` object.

:::warning Not available for public chats
Read receipts are disabled in [public chats](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/create#create-public-channel) by default. Control this with the [emitReadReceiptEvents](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/configuration#input-parameters) configuration parameter.
:::

### Method signature

```kotlin
channel.onReadReceiptReceived(callback: (receipt: ReadReceipt) -> Unit): AutoCloseable
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| callback | (receipt: | Yes |  | Function invoked when a read receipt event is received. |

The `ReadReceipt` object contains:

| Property | Description |
| --- | --- |
| `userId`Type: `String` | The ID of the user who read the message. |
| `lastReadTimetoken`Type: `Long` | The timetoken indicating how far the user has read in the channel. |

#### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface you can call to stop listening for read receipt events by invoking the `close()` method. |

### Sample code

Receive individual read receipt events on the `support` channel.

```kotlin
chat.getChannel("support").async { result ->
    result.onSuccess { channel ->
        val subscription = channel?.onReadReceiptReceived { receipt ->
            println("User ${receipt.userId} read up to timetoken ${receipt.lastReadTimetoken}")
        }

        // stop listening:
        // subscription?.close()
    }.onFailure { error ->
        println("Failed to get channel: $error")
    }
}
```

## Fetch read receipts

`fetchReadReceipts()` returns the current read status for all members of a channel. Use this to display read indicators when loading a conversation.

### Method signature

```kotlin
channel.fetchReadReceipts(
    limit: Int? = 100,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMemberKey>> = listOf(),
): PNFuture<ReadReceiptsResponse>
```

#### Input

| Parameter | Description |
| --- | --- |
| `limit`Type: `Int`Default: `100` | Number of members to return. Default and max is `100`. |
| `page`Type: `PNPage`Default: `null` | Pagination object for fetching next/previous results. |
| `filter`Type: `String`Default: `null` | Expression used to filter the results. |
| `sort`Type: `Collection<PNSortKey<PNMemberKey>>`Default: `listOf()` | A collection to specify the sort order. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<ReadReceiptsResponse>` | Response containing a list of `ReadReceipt` objects and pagination tokens. |

The `ReadReceiptsResponse` object contains:

| Property | Description |
| --- | --- |
| `receipts`Type: `List<ReadReceipt>` | List of read receipts, one per member. |
| `next`Type: `PNPage.PNNext?` | Pagination token for the next page. |
| `prev`Type: `PNPage.PNPrev?` | Pagination token for the previous page. |
| `total`Type: `Int` | Total number of members matching the query. |
| `status`Type: `Int` | HTTP status code of the operation. |

### Sample code

Fetch read receipts for all members of the `support` channel.

```kotlin
chat.getChannel("support").async { result ->
    result.onSuccess { channel ->
        channel?.fetchReadReceipts()?.async { receiptsResult ->
            receiptsResult.onSuccess { response ->
                response.receipts.forEach { receipt ->
                    println("User ${receipt.userId} last read: ${receipt.lastReadTimetoken}")
                }
            }.onFailure { error ->
                println("Failed to fetch read receipts: $error")
            }
        }
    }.onFailure { error ->
        println("Failed to get channel: $error")
    }
}
```

## Get read receipts (deprecated)

:::warning Deprecated method
`streamReadReceipts()` is deprecated. Use [onReadReceiptReceived()](#get-read-receipts) for real-time events or [fetchReadReceipts()](#fetch-read-receipts) for current status.
:::

`streamReadReceipts()` provides read status for messages on a channel. The method fetches member read status, listens for updates, and passes [receipt events](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/custom-events#events-for-read-receipts) to your callback.

### Method signature

```kotlin
channel.streamReadReceipts(callback: (receipts: Map<Long, List<String>>) -> Unit): AutoCloseable
```

#### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: n/aDefault: n/a | Callback function passed as a parameter. It defines the custom behavior to be executed when receiving a read confirmation status on the joined channel. |
| `> receipts` *Type: `Map<Long, List<String>>`Default: n/a | The received object that maps message timetokens (as `Long`) to users who last read these messages. |

#### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface you can call to stop listening for message read receipts and clean up resources when they are no longer needed by invoking the `close()` method. |

### Sample code

```kotlin
chat.getChannel("support").async { result ->
    result.onSuccess { channel ->
        val receiptStream = channel.streamReadReceipts { receipts ->
            receipts.forEach { (messageTimetoken, users) ->
                println("Message $messageTimetoken was read by: $users")
            }
        }
        // receiptStream.close()
    }.onFailure { error ->
        println("Failed to get channel: $error")
    }
}
```