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

> 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/chat-sdk/build/features/messages/unread). First, [set the last read timetoken](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/unread#mark-messages-as-read-one-channel) for each user on a channel.
:::

## Get read receipts

`onReadReceiptReceived()` listens for incoming [receipt events](https://www.pubnub.com/docs/chat/chat-sdk/build/features/custom-events#events-for-read-receipts) on a channel. The callback is invoked each time a member updates their last read message.

:::warning Not available for public chats
Read receipts are disabled in [public chats](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/create#create-public-channel).
:::

:::note Control which channel types emit read receipts
`emitReadReceiptEvents` in [Chat.init()](https://www.pubnub.com/docs/chat/chat-sdk/build/configuration#input-parameters) controls which channel types emit `receipt` events. By default, `direct` and `group` channels emit receipts and `public` channels do not. Refer to [Configuration](https://www.pubnub.com/docs/chat/chat-sdk/build/configuration#input-parameters) for details.
:::

The `ReadReceipt` type has the following shape:

```ts
type ReadReceipt = {
    userId: string
    lastReadTimetoken: string
}
```

### Method signature

```ts
channel.onReadReceiptReceived(
    callback: (receipt: ReadReceipt) => void
): () => void
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| callback | n/a | Yes |  | Callback function passed as a parameter. It defines the custom behavior to be executed when receiving a read confirmation event on the joined channel. |
| → receipt | ReadReceipt | Yes |  | Object containing the `userId` of the member who read the message and the `lastReadTimetoken` indicating which message they last read. |

#### Output

| Type | Description |
| --- | --- |
| `() => void` | Function you can call to stop receiving read receipt events. |

### Sample code

Listen for read receipt events on the `support` channel.

```ts
// reference the "support" channel
const channel = await chat.getChannel("support")

const stopListening = channel.onReadReceiptReceived((receipt) => {
    console.log(`User ${receipt.userId} last read up to timetoken ${receipt.lastReadTimetoken}`)
})

// after some time...
stopListening()
```

## Fetch read receipts

`fetchReadReceipts()` retrieves a paginated list of read receipts for all members on a channel.

The `ReadReceiptsResponse` type has the following shape:

```ts
type ReadReceiptsResponse = {
    page: {
        next?: string
        prev?: string
    }
    total: number
    status: number
    receipts: ReadReceipt[]
}
```

### Method signature

```ts
channel.fetchReadReceipts(params?: {
    filter?: string
    sort?: object
    limit?: number
    page?: {
        next?: string
        prev?: string
    }
}): Promise<ReadReceiptsResponse>
```

#### Input

| Parameter | Description |
| --- | --- |
| `params`Type: `object`Default: n/a | Optional pagination and filtering parameters. |
| → `filter`Type: `string`Default: n/a | Expression used to filter the results. |
| → `sort`Type: `object`Default: n/a | Key-value pair of a property to sort by and sort direction. |
| → `limit`Type: `number`Default: `100` | Number of receipts to return. The default (and maximum) value is `100`. |
| → `page`Type: `object`Default: n/a | Object used for pagination. |
| → `next`Type: `string`Default: n/a | Token for forward pagination. |
| → `prev`Type: `string`Default: n/a | Token for backward pagination. Ignored if `next` is supplied. |

#### Output

| Parameter | Description |
| --- | --- |
| `Promise<ReadReceiptsResponse>`Type: `object` | Returned object containing `page`, `total`, `status`, and `receipts`. |
| → `page`Type: `object` | Pagination cursors. |
| → `total`Type: `number` | Total number of read receipts. |
| → `status`Type: `number` | HTTP status code of the response, like `200`. |
| → `receipts`Type: `ReadReceipt[]` | Array of read receipts. |

### Sample code

Fetch all read receipts for the `support` channel.

```ts
// reference the "support" channel
const channel = await chat.getChannel("support")

const { receipts, total } = await channel.fetchReadReceipts()
console.log(`Total receipts: ${total}`)
receipts.forEach((receipt) => {
    console.log(`User ${receipt.userId} last read up to timetoken ${receipt.lastReadTimetoken}`)
})
```

## Deprecated method

:::warning Deprecated
`streamReadReceipts()` is deprecated. Use [onReadReceiptReceived()](#get-read-receipts) to listen for real-time events and [fetchReadReceipts()](#fetch-read-receipts) to retrieve historical data instead.
:::

`streamReadReceipts()` provided read status for messages on a channel. The method fetched member read status, listened for updates, and passed `receipt` events to your callback.

```ts
channel.streamReadReceipts(callback: (receipts: {
    [key: string]: string[];
}) => unknown): Promise<() => void>
```

### Sample code

```ts
// reference the "support" channel
const channel = await chat.getChannel("support")

const stopReceipts = await channel.streamReadReceipts((receipts) => {
  // callback to handle current receipts data
})

// after some time...
stopReceipts()
```