# Channels

When you retrieve a channel from the API (e.g. using query channels), the read state for all members is included in the response. This allows you to display which messages are read by each user. For each member, we include the last time he or she marked the channel as read.

<codetabs>

<codetabs-item value="swift" label="Swift">

```swift
let channelController = client.channelController(for: .init(type: .messaging, id: "general"))

channelController.synchronize() { error in
  if error == nil {
    channelController.channel?.reads
  }
}
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
const channel = client.channel("messaging", "test");
await channel.watch();

console.log(channel.state.read);

//{ '2fe6019c-872f-482a-989e-ecf4f786501b':
// { user:
//  {
//   id: '2fe6019c-872f-482a-989e-ecf4f786501b',
//   role: 'user',
//   created_at: '2019-04-24T13:09:19.664378Z',
//   updated_at: '2019-04-24T13:09:23.784642Z',
//   last_active: '2019-04-24T13:09:23.781641Z',
//   online: true
//  },
//  last_read: '2019-04-24T13:09:21.623Z',
// }
//}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final response = await channel.watch();

// readState is the list of read states for each user on the channel
List<Read> readState = response.read;
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Get channel
val queryChannelRequest = QueryChannelRequest().withState()

client.queryChannel(
  channelType = "channel-type",
  channelId = "channel-id",
  request = queryChannelRequest,
).enqueue { result ->
  if (result.isSuccess) {
    // readState is the list of read states for each user on the channel
    val readState: List<ChannelUserRead> = result.data().read
  } else {
    // Handle result.error()
  }
}
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
const FChannelProperties Properties{TEXT("channel-type"), TEXT("channel-id")};
Client->WatchChannel(
  Properties,
  [](UChatChannel* Channel)
  {
    // ReadState is the list of read states for each user on the channel
    const TArray<FRead>& ReadState = Channel->State.Read;
  });
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Get channel
QueryChannelRequest queryChannelRequest = new QueryChannelRequest().withState();

client.queryChannel("channel-type", "channel-id", queryChannelRequest).enqueue((result) -> {
  if (result.isSuccess()) {
    // readState is the list of read states for each user on the channel
    List<ChannelUserRead> readState = result.data().getRead();
  } else {
    // Handle result.error()
  }
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Every channel maintains a full list of read state for each channel member
foreach (var read in channel.Read)
{
  Debug.Log(read.User); // User
  Debug.Log(read.UnreadMessages); // How many unread messages
  Debug.Log(read.LastRead); // Last read date
}
```

</codetabs-item>

</codetabs>

### Unread Messages Per Channel

You can retrieve the count of unread messages for the current user on a channel like this:

<codetabs>

<codetabs-item value="swift" label="Swift">

```swift
let channelController = client.channelController(for: .init(type: .messaging, id: "general"))

class ChannelDelegate: ChatChannelControllerDelegate {
  func channelController(_ channelController: ChatChannelController,
              didUpdateChannel channel: EntityChange<ChatChannel>) {
    channelController.channel?.unreadCount
  }
}

channelController.delegate = ChannelDelegate()

channelController.synchronize()
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
channel.countUnread();
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
channel.unreadCount();
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Get channel
val queryChannelRequest = QueryChannelRequest().withState()

client.queryChannel(
  channelType = "channel-type",
  channelId = "channel-id",
  request = queryChannelRequest,
).enqueue { result ->
  if (result.isSuccess) {
    // Unread count for current user
    val unreadCount = result.data().unreadCount
  } else {
    // Handle result.error()
  }
}
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Channel->State.UnreadCount();
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Get channel
QueryChannelRequest queryChannelRequest = new QueryChannelRequest().withState();

client.queryChannel("channel-type", "channel-id", queryChannelRequest).enqueue((result) -> {
  if (result.isSuccess()) {
    // Unread count for current user
    Integer unreadCount = result.data().getUnreadCount();
  } else {
    // Handle result.error()
  }
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Every channel maintains a full list of read state for each channel member
foreach (var read in channel.Read)
{
  Debug.Log(read.User); // User
  Debug.Log(read.UnreadMessages); // How many unread messages
  Debug.Log(read.LastRead); // Last read date
}
```

</codetabs-item>

</codetabs>

### Unread Mentions Per Channel

You can retrieve the count of unread messages mentioning the current user on a channel like this:

<codetabs>

<codetabs-item value="swift" label="Swift">

```swift
let channelController = client.channelController(for: .init(type: .messaging, id: "general"))

class ChannelDelegate: ChatChannelControllerDelegate {
  func channelController(_ channelController: ChatChannelController,
              didUpdateChannel channel: EntityChange<ChatChannel>) {
    channelController.channel?.unreadCount.mentionedMessages
  }
}

channelController.delegate = ChannelDelegate()

channelController.synchronize()
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
channel.countUnreadMentions();
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Get channel
val queryChannelRequest = QueryChannelRequest().withState()
val currentUser = client.getCurrentUser()
if (currentUser == null) {
  // Handle user not connected state
  return
}

client.queryChannel(
  channelType = "channel-type",
  channelId = "channel-id",
  request = queryChannelRequest,
).enqueue { result ->
  if (result.isSuccess) {
    // Unread mentions
    val channel = result.data()
    val unreadCount = channel.countUnreadMentionsForUser(currentUser)
  } else {
    // Handle result.error()
  }
}
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Get channel
QueryChannelRequest queryChannelRequest = new QueryChannelRequest().withState();
User currentUser = client.getCurrentUser();
if (currentUser == null) {
  // Handle user not connected state
  return;
}

client.queryChannel("channel-type", "channel-id", queryChannelRequest).enqueue((result) -> {
  if (result.isSuccess()) {
    // Unread mentions
    Channel channel = result.data();
    Integer unreadCount = ChannelExtensionKt.countUnreadMentionsForUser(channel, currentUser);
  } else {
    // Handle result.error()
  }
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/
```

</codetabs-item>

</codetabs>

### Mark All As Read

You can mark all channels as read for a user like this:

<codetabs>

<codetabs-item value="swift" label="Swift">

```swift
let channelListController = client.channelListController(query: .init(filter: .containMembers(userIds: ["joe"])))
channelListController.markAllRead()
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
// client-side
await client.markAllRead();

// mark all as read for one user server-side
await serverSideClient.markAllRead({ user: { id: "myid" } });
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// mark all messages on all channels as read for one user, server-side
$client->markAllRead('user-id');
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
await client.markRead();
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
client.markAllRead().enqueue { result ->
  if (result.isSuccess) {
    //Handle success
  } else {
    //Handle failure
  }
}
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Client->MarkAllRead();
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
client.markAllRead().enqueue((result) -> {
  if (result.isSuccess()) {
    //Handle success
  } else {
    //Handle failure
  }
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Mark this message as last read
await message.MarkMessageAsLastReadAsync();

// Mark whole channel as read
await channel.MarkChannelReadAsync();
```

</codetabs-item>

</codetabs>

---

This page was last updated at 2025-08-15T14:14:38.513Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/ios-swift/unread_channel/](https://getstream.io/chat/docs/ios-swift/unread_channel/).