---
source_url: https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/channel-groups
title: Channel groups
updated_at: 2026-05-29T11:08:15.082Z
---

> 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


# Channel groups

Channel groups let you subscribe to multiple channels with a single subscription. Add channels to a group and receive messages from all of them at once.

Use channel groups to:

* Subscribe to all user channels with one call
* Monitor presence across multiple channels
* Manage subscriptions dynamically without reconnecting

Publishing to a channel group is not supported. Publish to each channel individually.

:::note Requires Stream Controller
Enable *Stream Controller* for your key in the [Admin Portal](https://admin.pubnub.com/). See the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for details.
:::

## Get channel group reference

Get a reference to a channel group with `getChannelGroup()`. This returns a handle to manage the group without creating it on the server.

If the group exists, the reference points to it. Otherwise, the handle creates the group when you add channels.

### Method signature

This method takes the following parameters:

```kotlin
chat.getChannelGroup(id: String): ChannelGroup
```

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| id | String | Yes |  | Unique identifier for the channel group. |

#### Output

| Type | Description |
| --- | --- |
| `ChannelGroup` | A [ChannelGroup](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/channel-group) object you can use to manage the group. |

### Sample code

Get a reference to a channel group named `my-channel-group`.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")
```

## Remove channel group

Delete a channel group from the server with `removeChannelGroup()`.

### Method signature

This method takes the following parameters:

```kotlin
chat.removeChannelGroup(id: String): PNFuture<Unit>
```

#### Input

| Parameter | Description |
| --- | --- |
| `id` *Type: `String`Default: n/a | Unique identifier of the channel group to remove. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns an empty response when the channel group is successfully removed. |

### Sample code

Remove a channel group named `my-channel-group`.

```kotlin
chat.removeChannelGroup("my-channel-group").async { result ->
    result.onSuccess {
        // Channel group removed successfully
    }.onFailure {
        // Handle failure
    }
}
```

## List channels

Get a paginated list of all channels in a channel group with `listChannels()`.

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.listChannels(
    filter: String? = null,
    sort: Collection<PNSortKey<PNKey>> = listOf(),
    limit: Int? = null,
    page: PNPage? = null
): PNFuture<GetChannelsResponse>
```

#### Input

| Parameter | Description |
| --- | --- |
| `filter`Type: `String`Default: n/a | Expression used to filter the results. Returns only the channels whose properties satisfy the given expression. The filter language is [defined here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNKey>>`Default: `listOf()` | A collection to specify the sort order. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify the sorting direction. For example: `listOf(PNSortKey.asc(PNKey.NAME))`. |
| `limit`Type: `Int`Default: `100` | Number of objects to return in response. The default (and maximum) value is `100`. |
| `page`Type: `PNPage`Default: n/a | Object used for pagination to define which previous or next result page you want to fetch. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<GetChannelsResponse>` | `PNFuture` containing a set of channels with pagination information (`next`, `prev`, `total`). |

### Sample code

List all channels in a channel group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

channelGroup.listChannels().async { result ->
    result.onSuccess { response ->
        response.channels.forEach { channel ->
            println("Channel: ${channel.id}")
        }
    }.onFailure {
        // Handle failure
    }
}
```

## Add channels

Add `Channel` entities to a channel group with `addChannels()`.

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.addChannels(channels: Collection<Channel>): PNFuture<Unit>
```

#### Input

| Parameter | Description |
| --- | --- |
| `channels` *Type: `Collection<Channel>`Default: n/a | Collection of [Channel](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/channel) entities to add to the group. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns an empty response when channels are successfully added. |

### Sample code

Add two channels to a channel group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

chat.getChannel("support-channel").async { result ->
    result.onSuccess { supportChannel ->
        chat.getChannel("general-channel").async { result2 ->
            result2.onSuccess { generalChannel ->
                if (supportChannel != null && generalChannel != null) {
                    channelGroup.addChannels(listOf(supportChannel, generalChannel))
                        .async { addResult ->
                            addResult.onSuccess {
                                // Channels added successfully
                            }.onFailure {
                                // Handle failure
                            }
                        }
                }
            }
        }
    }
}
```

## Add channel identifiers

Add channels to a group by ID with `addChannelIdentifiers()`. This avoids fetching full `Channel` entities.

:::note No validation
This method doesn't validate whether channels with the given IDs exist. Make sure the channel IDs are valid before adding them.
:::

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.addChannelIdentifiers(ids: Collection<String>): PNFuture<Unit>
```

#### Input

| Parameter | Description |
| --- | --- |
| `ids` *Type: `Collection<String>`Default: n/a | Collection of channel IDs to add to the group. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns an empty response when channel identifiers are successfully added. |

### Sample code

Add channels by their IDs.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

channelGroup.addChannelIdentifiers(listOf("support-channel", "general-channel")).async { result ->
    result.onSuccess {
        // Channel identifiers added successfully
    }.onFailure {
        // Handle failure
    }
}
```

## Remove channels

Remove `Channel` entities from a channel group with `removeChannels()`.

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.removeChannels(channels: Collection<Channel>): PNFuture<Unit>
```

#### Input

| Parameter | Description |
| --- | --- |
| `channels` *Type: `Collection<Channel>`Default: n/a | Collection of [Channel](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/channel) entities to remove from the group. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns an empty response when channels are successfully removed. |

### Sample code

Remove channels from a channel group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

// Assuming you have Channel references
channelGroup.removeChannels(listOf(supportChannel, generalChannel)).async { result ->
    result.onSuccess {
        // Channels removed successfully
    }.onFailure {
        // Handle failure
    }
}
```

## Remove channel identifiers

Remove channels from a group by ID with `removeChannelIdentifiers()`.

:::note No validation
This method doesn't validate whether channels with the given IDs exist in the group. Make sure the channel IDs are valid before removing them.
:::

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.removeChannelIdentifiers(ids: Collection<String>): PNFuture<Unit>
```

#### Input

| Parameter | Description |
| --- | --- |
| `ids` *Type: `Collection<String>`Default: n/a | Collection of channel IDs to remove from the group. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns an empty response when channel identifiers are successfully removed. |

### Sample code

Remove channels by their IDs.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

channelGroup.removeChannelIdentifiers(listOf("support-channel", "general-channel")).async { result ->
    result.onSuccess {
        // Channel identifiers removed successfully
    }.onFailure {
        // Handle failure
    }
}
```

## Watch channel group

Subscribe to all channels in the group and receive messages with `onMessageReceived()`. The callback fires whenever a message arrives on any channel in the group.

:::warning Deprecated method
`connect()` is deprecated. Use `onMessageReceived()` instead. Both methods have the same signature and behavior.
:::

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.onMessageReceived(callback: (Message) -> Unit): AutoCloseable
```

#### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: `(Message) -> Unit`Default: n/a | Callback function invoked whenever a message is received on any channel in the group. |

#### Output

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

### Sample code

Start receiving messages from all channels in a group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

val subscription = channelGroup.onMessageReceived { message ->
    println("Received message on channel ${message.channelId}: ${message.text}")
}

// Later, when you want to stop receiving messages
subscription.close()
```

## Get present users

Get a list of users currently present on any channel in the group with `whoIsPresent()`.

:::note Requires Presence
This method requires that [Presence is enabled](https://youtu.be/i2yLIqmvFD0) for your app's keyset in the [Admin Portal](https://admin.pubnub.com/).
:::

### Method signature

This method has the following signature:

```kotlin
channelGroup.whoIsPresent(
    limit: Int = 1000,
    offset: Int? = null
): PNFuture<Map<String, Collection<String>>>
```

#### Input

| Parameter | Description |
| --- | --- |
| `limit`Type: `Int`Default: `1000` | Maximum number of occupants to return per channel. Valid range: 0-1000. Use `0` to get occupancy counts without user details. |
| `offset`Type: `Int?`Default: `null` | Zero-based starting index for pagination. Returns occupants starting from this position in the list. Must be >= 0. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Map<String, Collection<String>>>` | A map where each key is a channel ID and the value is a collection of user IDs present on that channel. |

### Sample code

Get all users present on channels in a group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

channelGroup.whoIsPresent().async { result ->
    result.onSuccess { presenceByChannel ->
        presenceByChannel.forEach { (channelId, userIds) ->
            println("Channel $channelId has users: $userIds")
        }
    }.onFailure {
        // Handle failure
    }
}
```

## Stream presence

Receive real-time updates when users join or leave any channel in the group with `onPresenceChanged()`.

:::warning Deprecated method
`streamPresence()` is deprecated. Use `onPresenceChanged()` instead. Both methods have the same signature and behavior.
:::

:::note Requires Presence
This method requires that [Presence is enabled](https://youtu.be/i2yLIqmvFD0) for your app's keyset in the [Admin Portal](https://admin.pubnub.com/).
:::

### Method signature

This method takes the following parameters:

```kotlin
channelGroup.onPresenceChanged(
    callback: (presenceByChannels: Map<String, Collection<String>>) -> Unit
): AutoCloseable
```

#### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: `(Map<String, Collection<String>>) -> Unit`Default: n/a | Callback function invoked when presence changes. Receives a map where each key is a channel ID and the value is a collection of user IDs present on that channel. |

#### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface you can call to stop receiving presence updates by invoking the `close()` method. |

### Sample code

Stream presence updates for all channels in a group.

```kotlin
val channelGroup = chat.getChannelGroup("my-channel-group")

val subscription = channelGroup.onPresenceChanged { presenceByChannel ->
    presenceByChannel.forEach { (channelId, userIds) ->
        println("Channel $channelId now has users: $userIds")
    }
}

// Later, when you want to stop receiving presence updates
subscription.close()
```