---
source_url: https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/unread
title: Unread messages
updated_at: 2026-09-30T07:20:08.000Z
---

# Unread messages

> For AI agents: documentation index at https://www.pubnub.com/llms-full.txt

Track unread message counts for users who reconnect after being offline.

`lastReadMessageTimetoken` on the [Membership](https://www.pubnub.com/docs/chat/chat-sdk/learn/chat-entities/membership.md) object stores when a user last read messages on a channel. This is set automatically on [join()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/join.md) or [invite()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/invite.md#invite-one-user). Update it based on user actions (scrolling, app focus, etc.) using [mark as read](#mark-messages-as-read-one-channel) methods.

:::note Requires App Context and Message Persistence
Enable [App Context](https://youtu.be/9UEoSlngpYI) and [Message Persistence](https://youtu.be/qLMtbINWGig) in the [Admin Portal](https://admin.pubnub.com/).
:::

## Get last read message

`lastReadMessageTimetoken` returns the timetoken marking the user's last read position on a channel. This timetoken doesn't always correspond to an actual message. Use it to display unread markers in your UI.

### Method signature

This method has the following signature:

```ts
membership.lastReadMessageTimetoken: string
```

#### Properties

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| lastReadMessageTimetoken | string | Optional |  | Value of the returned timetoken. |

### Sample code

Get the timetoken of the last message read by the `support_agent_15` user on the `support` channel.

```ts
// reference the "support_agent_15" user
const user = await chat.getUser("support_agent_15")

// get the list of all user memberships and filter out the right channel
const membership = await user.getMemberships({
    filter: "channel.id == 'support'"
})

// 
membership.lastReadMessageTimetoken
```

## Get unread messages count (one channel)

`getUnreadMessagesCount()` returns the number of unread messages on a channel. This counts all messages after the last read timetoken, including your own messages.

##### Under the hood

`getUnreadMessagesCount()` calls the Message Persistence API and the JavaScript SDK [messageCounts()](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback.md#message-counts) method.

### Method signature

This method has the following signature:

```ts
membership.getUnreadMessagesCount(): Promise<number | false>
```

#### Input

This method doesn't take any parameters.

#### Output

| Type | Description |
| --- | --- |
| `Promise<number>` or `Promise<false>` | Retrieves from Message Persistence the number of all messages unread by a given user on a given channel from the last read message. The method returns `false` when there is no [last read message timetoken](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/unread.md#mark-messages-as-read-one-channel) set on the [Message object](https://www.pubnub.com/docs/chat/chat-sdk/learn/chat-entities/message.md). |

### Sample code

Get the number of all messages unread by the `support_agent_15` user on the `support` channel.

```ts
// reference the "support_agent_15" user
const user = await chat.getUser("support_agent_15")

// get the list of all user memberships and filter out the right channel
const membership = await user.getMemberships({
    filter: "channel.id == 'support'"
})

// get the number of unread messages
await membership.getUnreadMessagesCount()
```

## Get unread messages count (all channels)

`fetchUnreadMessagesCounts()` returns unread counts for all joined channels with unread messages (channels with zero unread are excluded). Counts include all messages after the last read timetoken, including your own.

##### Under the hood

`fetchUnreadMessagesCounts()` calls the Message Persistence API and the JavaScript SDK [messageCounts()](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback.md#message-counts) method.

:::note Unread counts and filtering
Filters support `channel.*` fields plus `status`, `type`, `custom` (not `uuid.*`). Unread counts include your own messages. See [Memberships filters](https://www.pubnub.com/docs/data-storage/metadata/filtering.md).
:::

### Method signature

This method has the following signature:

```ts
chat.fetchUnreadMessagesCounts({
    filter?: string,
    sort?: object,
    limit?: number,
    page?: {
        next?: string,
        prev?: string
    }
}): Promise<{
        countsByChannel: Array<{
            channel: Channel;
            membership: Membership;
            count: number;
        }>;
        page: {
            next: string | undefined;
            prev: string | undefined;
        };
    }>
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| filter | string (Memberships filter) | Optional |  | Filter expression evaluated against [channel memberships](https://www.pubnub.com/docs/data-storage/metadata/filtering.md) only. Allowed targets: `channel.*` plus common fields (`status`, `type`, `custom`). `uuid.*` fields aren't supported. |
| sort | object | Optional |  | Key-value pair of a property to sort by, and a sort direction. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify the sorting direction, or specify `null` to take the default sorting direction (ascending). For example: `{name: "asc"}`. By default, the items are sorted by the last updated date. |
| limit | number | Optional | `100` | Number of objects to return in response. The default (and maximum) value is `100`. |
| page | object | Optional |  | Object used for pagination to define which previous or next result page you want to fetch. |
| > next | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
| > prev | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the `next` parameter is supplied. |

#### Output

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Promise<> | object | Optional |  | Returned object containing these fields: `countsByChannel` and `page`. |
| > countsByChannel | Array<object> | Optional |  | Array of objects containing channel, membership, and count information. |
| >> channel | Channel | Optional |  | Channel with unread messages. |
| >> membership | Membership | Optional |  | Returned [Membership object](https://www.pubnub.com/docs/chat/chat-sdk/learn/chat-entities/membership.md) showing the user-channel data. |
| >> count | number | Optional |  | Total number of messages unread by the current user on a given channel. |
| > page | object | Optional |  | Object containing pagination information. |
| >> next | string \| undefined | Optional |  | Token for fetching the next page of results. |
| >> prev | string \| undefined | Optional |  | Token for fetching the previous page of results. |

### Sample code

Get the number of all messages unread by the `support_agent_15` user on all joined channels.

```ts
// reference the "support_agent_15" user
const user = await chat.getUser("support_agent_15")

// get all messages unread by that user
const result = await chat.fetchUnreadMessagesCounts()

// access the counts for each channel
const countsByChannel = result.countsByChannel

// access pagination tokens if needed
const { next, prev } = result.page
```

To avoid counting your own recently sent messages as unread, ensure your app updates the [last read timetoken](#mark-messages-as-read-one-channel).

## Mark messages as read (one channel)

`setLastReadMessage()` and `setLastReadMessageTimetoken()` set the last read timetoken for counting unread messages. Bind these to user actions in your app.

##### Under the hood

`setLastReadMessage()` and `setLastReadMessageTimetoken()` call App Context API and the JavaScript SDK [setMemberships()](https://www.pubnub.com/docs/sdks/javascript/api-reference/objects.md#set-channel-memberships) method.

Setting the last read message for users lets you implement the [Read Receipts](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/read-receipts.md) feature and monitor which channel member read which message.

### Method signature

These methods take the following parameters:

* `setLastReadMessage()`

   ```ts
   membership.setLastReadMessage(
       message: Message
   ): Promise<Membership>
   ```

* `setLastReadMessageTimetoken()`

   ```ts
   membership.setLastReadMessageTimetoken(
       timetoken: string
   ): Promise<Membership>
   ```

#### Input

| Parameter | Required by setLastReadMessage() | Required by setLastReadMessageTimetoken() | Description |
| --- | --- | --- | --- |
| message | Message | Optional |  | Yes | No | Last read message on a given channel with the timestamp that gets added to the [user-channel membership](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/membership.md#update) as the `custom` parameter called `lastReadMessageTimetoken`. |
| timetoken | string | Optional |  | No | Yes | Timetoken of the last read message on a given channel that gets added to the [user-channel membership](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/membership.md#update) as the `custom` parameter called `lastReadMessageTimetoken`. |

#### Output

| Type | Description |
| --- | --- |
| `Promise<Membership>` | Returned `Membership` object updated with the `lastReadMessageTimetoken` custom parameter. |

### Sample code

Set the message with the `16200000000000001` timetoken as the last read message for the `support_agent_15` user on the `support` channel.

* `setLastReadMessage()`

   ```ts
   // reference the "support_agent_15" user
   const user = await chat.getUser("support_agent_15")

   // get the list of all user memberships and filter out the right channel
   const membership = await user.getMemberships({
       filter: "channel.id == 'support'"
   })

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

   // return the message object with the "16200000000000001" timetoken
   const message = await channel.getMessage("16200000000000001")

   // assuming a single membership which matches the filter
   await membership.memberships[0].setLastReadMessage(message) 
   ```

* `setLastReadMessageTimetoken()`

   ```ts
   // reference the "support_agent_15" user
   const user = await chat.getUser("support_agent_15")

   // get the list of all user memberships and filter out the right channel
   const membership = await user.getMemberships({
       filter: "channel.id == 'support'"
   })

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

   // return the message object with the "16200000000000001" timetoken
   const message = await channel.getMessage("16200000000000001")

   // assuming a single membership which matches the filter
   await membership.memberships[0].setLastReadMessageTimetoken(message.timetoken)
   ```

## Mark messages as read (all channels)

`markAllMessagesAsRead()` marks all unread messages as read on all joined channels.

##### Under the hood

`markAllMessagesAsRead()` calls Message Persistence API and the JavaScript SDK [getMemberships()](https://www.pubnub.com/docs/sdks/javascript/api-reference/objects.md#channel-memberships), [setMemberships()](https://www.pubnub.com/docs/sdks/javascript/api-reference/objects.md#set-channel-memberships), and [fetchMessages()](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback.md#fetch-history) methods.

### Method signature

This method has the following signature:

```ts
chat.markAllMessagesAsRead({
    filter?: string,
    sort?: object,
    limit?: number,
    page?: {
        next?: string,
        prev?: string 
    }
}): Promise<{
        page: {
          next: string,
          prev: string
        },
        total: number,
        status: number,
        memberships: Membership[]
}>
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| filter | string (Memberships filter) | Optional |  | Expression used to filter the results. Returns only these messages whose properties satisfy the given expression. The filtering language is [defined here](https://www.pubnub.com/docs/data-storage/metadata/filtering.md). |
| sort | object | Optional |  | Key-value pair of a property to sort by, and a sort direction. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify the sorting direction, or specify `null` to take the default sorting direction (ascending). For example: `{name: "asc"}`. By default, the items are sorted by the last updated date. |
| limit | number | Optional | `100` | Number of objects to return in response. The default (and maximum) value is `100`. |
| page | object | Optional |  | Object used for pagination to define which previous or next result page you want to fetch. |
| > next | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
| > prev | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the `next` parameter is supplied. |

#### Output

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Promise<> | object | Optional |  | Returned object containing these fields: `page`, `total`, `status`, and `memberships`. |
| > page | object | Optional |  | Object used for pagination to define which previous or next result page you want to fetch. |
| >> next | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
| >> prev | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the `next` parameter is supplied. |
| > total | number | Optional |  | Total number of messages marked as read. |
| > status | number | Optional |  | Status code of a server response, like `200`. |
| > memberships | Membership[] | Optional |  | List of all related memberships. |

### Sample code

Mark the total number of 50 messages as read and specify you want to fetch the results from the next page using a string that was previously returned from the PubNub server.

```ts
await chat.markAllMessagesAsRead(
    {
        limit: 50,
        page: {
            next: "<returned_random_string>"
        }
    }
)
```

## Get unread messages count (all channels) (deprecated)

:::warning Deprecated
Use [fetchUnreadMessagesCounts()](#get-unread-messages-count-all-channels) instead.
:::

`getUnreadMessagesCounts()` returns unread counts for all joined channels.

##### Under the hood

`getUnreadMessagesCounts()` calls the Message Persistence API and the JavaScript SDK [messageCounts()](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback.md#message-counts) method.

### Method signature

This method has the following signature:

```ts
chat.getUnreadMessagesCounts({
    filter?: string,
    sort?: object,
    limit?: number,
    page?: {
        next?: string,
        prev?: string
    }
}): Promise<{
        channel: Channel,
        membership: Membership,
        count: number
    }[]>
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| filter | string (Memberships filter) | Optional |  | Filter expression evaluated against [channel memberships](https://www.pubnub.com/docs/data-storage/metadata/filtering.md) only. Allowed targets: `channel.*` plus common fields (`status`, `type`, `custom`). `uuid.*` fields aren't supported. |
| sort | object | Optional |  | Key-value pair of a property to sort by, and a sort direction. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify the sorting direction, or specify `null` to take the default sorting direction (ascending). For example: `{name: "asc"}`. By default, the items are sorted by the last updated date. |
| limit | number | Optional | `100` | Number of objects to return in response. The default (and maximum) value is `100`. |
| page | object | Optional |  | Object used for pagination to define which previous or next result page you want to fetch. |
| > next | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
| > prev | string | Optional |  | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the `next` parameter is supplied. |

#### Output

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Promise<> | object | Optional |  | Returned object containing these fields: `channel`, `membership`, and `count`. The method returns an array of such objects corresponding to all channel memberships. |
| > channel | Channel | Optional |  | Channel with unread messages. |
| > membership | Membership | Optional |  | Returned [Membership object](https://www.pubnub.com/docs/chat/chat-sdk/learn/chat-entities/membership.md) showing the user-channel data. |
| > count | number | Optional |  | Total number of messages unread by the current user on a given channel. |

### Sample code

Get the number of all messages unread by the `support_agent_15` user on all joined channels.

```ts
// reference the "support_agent_15" user
const user = await chat.getUser("support_agent_15")

// get all messages unread by that user
await chat.getUnreadMessagesCounts()
```

Last updated at: 2026-09-30T07:20:08.000Z
