---
source_url: https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/membership
title: Manage the user-channel membership relationship
updated_at: 2026-06-12T11:22:51.969Z
---

> 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


# Manage the user-channel membership relationship

:::note Requires App Context
Enable [App Context](https://youtu.be/9UEoSlngpYI) for your keyset in the [Admin Portal](https://admin.pubnub.com/).
:::

A [Membership entity](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) is created when a user [joins](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/join) or is [invited](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/invite) to a channel, and ends when the user [leaves](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/leave).

## Get members

Get all members of a channel with `getMembers()`.

### Method signature

This method takes the following parameters:

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

#### Input

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| limit | Int | Optional | `100` | Number of objects to return in response. The default (and maximum) value is `100`. |
| page | PNPage | Optional |  | Object used for pagination to define which previous or next result page you want to fetch. |
| filter | String | Optional |  | Expression used to filter the results. Returns only these members whose properties satisfy the given expression. The filter language is [defined here](https://www.pubnub.com/docs/general/metadata/filtering). |
| sort | Collection<PNSortKey<PNMemberKey>> | Optional | `listOf()` | A collection to specify the sort order. 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"}`. Unless specified otherwise, the items are sorted by the last updated date. Defaults to an empty list. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<MembersResponse>` | `PNFuture` containing a set of channel members with membership `status`, `total` number of members, and `next` and `prev` pages. |

### Sample code

List all members of the `support` channel on the `premium` support plan.

```kotlin
// reference the "channel" object
chat.getChannel("support").async { result ->
    result.onSuccess { channel ->
        // get the list of all members with the premium support plan
        channel.getMembers(
            filter = "custom.support_plan == 'premium'"
        ).async { membersResult ->
            membersResult.onSuccess { membersResponse ->
                val membersList = membersResponse.members
                // handle success: membersList contains the list of members
            }.onFailure { error ->
                // handle failure
            }
        }
    }.onFailure { error ->
        // handle failure to fetch channel
    }
}
```

## Get membership

Get all channel [memberships](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) for a user with `getMemberships()`.

To list all channels, use [getChannels()](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/list) instead.

### Method signature

This method takes the following parameters:

```kotlin
user.getMemberships(
    limit: Int?,
    page: PNPage?,
    filter: String?,
    sort: Collection<PNSortKey<PNMembershipKey>> = listOf(),
): PNFuture<MembershipsResponse>
```

#### Input

| Parameter | Description |
| --- | --- |
| `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. |
| `filter`Type: `String`Default: n/a | Expression used to filter the results. Returns only these members whose properties satisfy the given expression. The filter language is [defined here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMembershipKey>>`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, or specify `null` to take the default sorting direction (ascending). For example: `{name: "asc"}`. Unless specified otherwise, the items are sorted by the last updated date. Defaults to an empty list. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<MembershipsResponse>` | `PNFuture` containing a set of memberships, their `status` and `total` number, and `next` and `prev` pages. |

### Sample code

Find out which channels the `support_agent_15` user is a member of.

```kotlin
// reference the "support_agent_15" user
chat.getUser("support_agent_15").async { result ->
    result.onSuccess { user ->
        // get the list of all user memberships
        user.getMemberships().async { membershipsResult ->
            membershipsResult.onSuccess { membershipsResponse ->
                val membershipsList = membershipsResponse.memberships
                // handle success: membershipsList contains the list of memberships
            }.onFailure { error ->
                // handle failure
            }
        }
    }.onFailure { error ->
        // handle failure to fetch user
    }
}
```

## Check membership

Check if a user is a member of a channel, or retrieve a specific membership.

### Check from channel

Use `hasMember()` to check if a user is a member, or `getMember()` to retrieve the membership.

#### Method signature

```kotlin
channel.hasMember(userId: String): PNFuture<Boolean>

channel.getMember(userId: String): PNFuture<Membership?>
```

#### Input

| Parameter | Description |
| --- | --- |
| `userId` *Type: `String`Default: n/a | The ID of the user to check. |

#### Output

| Method | Description |
| --- | --- |
| `hasMember()`Type: `PNFuture<Boolean>` | `true` if the user is a member of the channel. |
| `getMember()`Type: `PNFuture<Membership?>` | The `Membership` object if found, or `null`. |

#### Sample code

```kotlin
// check if a user is a member
channel.hasMember("support_agent_15").async { result ->
    result.onSuccess { isMember ->
        println("Is member: $isMember")
    }.onFailure { error ->
        // handle failure
    }
}

// get the membership details
channel.getMember("support_agent_15").async { result ->
    result.onSuccess { membership ->
        if (membership != null) {
            println("Membership found: ${membership.user.id} on ${membership.channel.id}")
        } else {
            println("User is not a member")
        }
    }.onFailure { error ->
        // handle failure
    }
}
```

### Check from user

Use `isMemberOf()` to check if a user belongs to a channel, or `getMembership()` to retrieve the membership.

#### Method signature

```kotlin
user.isMemberOf(channelId: String): PNFuture<Boolean>

user.getMembership(channelId: String): PNFuture<Membership?>
```

#### Input

| Parameter | Description |
| --- | --- |
| `channelId` *Type: `String`Default: n/a | The ID of the channel to check. |

#### Output

| Method | Description |
| --- | --- |
| `isMemberOf()`Type: `PNFuture<Boolean>` | `true` if the user is a member of the channel. |
| `getMembership()`Type: `PNFuture<Membership?>` | The `Membership` object if found, or `null`. |

#### Sample code

```kotlin
// check if the user belongs to a channel
user.isMemberOf("support").async { result ->
    result.onSuccess { isMember ->
        println("Is member of support: $isMember")
    }.onFailure { error ->
        // handle failure
    }
}
```

## Get updates

Receive updates when [Membership objects](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) are edited:

* `streamUpdates()` - monitors a single membership
* `streamUpdatesOn()` - monitors multiple memberships

Receive real-time notifications when membership metadata changes or a membership is deleted:

* `onUpdated()` - fires when membership metadata is modified
* `onDeleted()` - fires when the membership is removed

### Method signature (entity-first)

* onUpdated() 1membership.onUpdated(callback: (membership: Membership) -> Unit): AutoCloseable
* onDeleted() 1membership.onDeleted(callback: () -> Unit): AutoCloseable

#### Input

| Parameter | Description |
| --- | --- |
| `callback` (in `onUpdated`) *Type: `(membership: Membership) -> Unit`Default: n/a | Function that receives the updated `Membership` object. |
| `callback` (in `onDeleted`) *Type: `() -> Unit`Default: n/a | Function invoked when the membership is deleted. |

#### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface that lets you stop receiving membership-related updates by invoking the `close()` method. |

### Sample code (entity-first)

```kotlin
// get a membership and listen for updates
chat.currentUser.getMemberships().async { result ->
    result.onSuccess { membershipsResponse ->
        val firstMembership = membershipsResponse.memberships.firstOrNull()
        firstMembership?.let {
            val subscription = it.onUpdated { updatedMembership ->
                println("Updated membership: $updatedMembership")
            }
        }
    }.onFailure { exception ->
        println("Failed to fetch memberships: $exception")
    }
}
```

### Deprecated methods

:::warning Deprecated methods
`streamUpdates()` is deprecated. Use `onUpdated()` and `onDeleted()` instead. `streamUpdatesOn()` remains supported.
:::

:::note Membership changes
These methods notify about field changes (metadata, status) for existing memberships, not additions or removals.
:::

Both methods accept a callback invoked when membership data changes. They subscribe to a channel and add an [objects event listener](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#event-listeners) for `membership` events, returning an `unsubscribe` function.

:::note Stream update behavior
* `streamUpdates()` returns the updated `Membership` object on each change (`null` if deleted)
* `streamUpdatesOn()` returns the complete list of monitored memberships on any change
:::

### Method signature

These methods take the following parameters:

* streamUpdates() 1membership.streamUpdates(callback: (membership: Membership?) -> Unit): AutoCloseable
* streamUpdatesOn() 1class Membership {2 companion object {3 fun streamUpdatesOn(4 memberships: Collection<Membership>,5 callback: (memberships: Collection<Membership>) -> Unit6 ): AutoCloseable7 }8}

#### Input

| Parameter | Required in `streamUpdates()` | Required in `streamUpdatesOn()` | Description |
| --- | --- | --- | --- |
| `memberships`Type: `Collection<Membership>`Default: n/a | No | Yes | A collection of [Membership objects](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) for which you want to get updates. |
| `callback`Type: `(membership: Membership?) -> Unit`Default: n/a | Yes | No | Function that takes a single `Membership` object. It defines the custom behavior to be executed when detecting membership changes. |
| `callback`Type: `(memberships: Collection<Membership>) -> Unit`Default: n/a | No | Yes | Function that takes a set of `Membership` objects. It defines the custom behavior to be executed when detecting membership changes. |

#### Output

| Type | Description |
| --- | --- |
| `AutoCloseable` | Interface that lets you stop receiving membership-related updates (`objects` events) by invoking the `close()` method. |

### Sample code

Get updates on the first user membership.

* streamUpdates() 1chat.currentUser.getMemberships().async { result ->2 result.onSuccess { membershipsResponse ->3 // handle success4 val firstMembership = membershipsResponse.memberships.firstOrNull()5 firstMembership?.let {6 val autoCloseable = it.streamUpdates { updatedMembership ->7 // The callback receives the entire updated Membership object each time a change occurs.8 if (updatedMembership != null) {9 println("Updated membership: $updatedMembership")10 } else {11 println("Membership was deleted")12 }13 }14 } ?: run {15 println("No memberships found.")16 }17 }.onFailure { exception ->18 // handle failure19 println("Failed to fetch memberships: $exception")20 }21}

Get updates on the first page of user memberships.

* streamUpdatesOn() 1chat.currentUser.getMemberships().async { result ->2 result.onSuccess { membershipsResponse ->3 // handle success4 val firstPageMemberships = membershipsResponse.memberships.take(10) // assuming one page has 10 memberships5 6 val autoCloseable = Membership.streamUpdatesOn(memberships = firstPageMemberships) { updatedMemberships ->7 // The callback receives the complete list of all memberships you're monitoring8 // each time any change occurs.9 if (updatedMemberships.isNotEmpty()) {10 updatedMemberships.forEach { updatedMembership ->11 println("Updated membership: $updatedMembership")12 }13 } else {14 println("No membership updates available.")15 }16 }17 }.onFailure { exception ->18 // handle failure19 println("Failed to fetch memberships: $exception")20 }21}

### Other examples

Stop listening to updates on the first user membership.

* streamUpdates() 1chat.currentUser.getMemberships().async { result ->2 result.onSuccess { membershipsResponse ->3 // handle success4 val firstMembership = membershipsResponse.memberships.firstOrNull()5 firstMembership?.let {6 val autoCloseable = it.streamUpdates { updatedMembership ->7 // The callback receives the entire updated Membership object each time a change occurs.8 if (updatedMembership != null) {9 println("Updated membership: $updatedMembership")10 } else {11 println("Membership was deleted")12 }13 }14 15 // logic to stop listening to updates can be placed here16 // for example, close `autoCloseable` after some condition or delay17 // this is just an example of stopping listening immediately for demonstration18 autoCloseable.close() // this stops listening to updates19 20 } ?: run {21 println("No memberships found.")22 }23 }.onFailure { exception ->24 // handle failure25 println("Failed to fetch memberships: $exception")26 }27}

Stop listening to updates on the first page of user memberships.

* streamUpdatesOn() 1chat.currentUser.getMemberships().async { result ->2 result.onSuccess { membershipsResponse ->3 // handle success4 val firstPageMemberships = membershipsResponse.memberships.take(10) // assuming one page has 10 memberships5 6 val autoCloseable = Membership.streamUpdatesOn(memberships = firstPageMemberships) { updatedMemberships ->7 // The callback receives the complete list of all memberships you're monitoring8 // each time any change occurs.9 if (updatedMemberships.isNotEmpty()) {10 updatedMemberships.forEach { updatedMembership ->11 println("Updated membership: $updatedMembership")12 }13 } else {14 println("No membership updates available.")15 }16 }17 18 // logic to stop listening to updates can be placed herel19 // for example, close `autoCloseable` after some condition or delay20 // this is just an example of stopping listening immediately for demonstration21 autoCloseable.close() // this stops listening to updates22 23 }.onFailure { exception ->24 // handle failure25 println("Failed to fetch memberships: $exception")26 }27}

## Delete membership

Delete a [membership](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) with `delete()`.

### Method signature

```kotlin
membership.delete(): PNFuture<Unit>
```

#### Input

This method doesn't take any parameters.

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Unit>` | Returns when the membership is successfully removed. |

### Sample code

```kotlin
val channel: Channel
// ...

channel.join().async { joinResult ->
    joinResult.onSuccess { membership ->
        membership.delete().async { deleteResult ->
            deleteResult.onSuccess {
                // handle success
                println("Membership deleted successfully")
            }.onFailure {
                // handle failure
                println("Failed to delete membership: ${it.message}")
            }
        }
    }.onFailure {
        // handle failure
    }
}
```

## Update

Update a user's channel [membership](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/membership) information with `update()`.

### Method signature

This method takes the following parameters:

```kotlin
membership.update(
    status: String? = null,
    type: String? = null,
    custom: CustomObject? = null
): PNFuture<Membership>
```

#### Input

| Parameter | Description |
| --- | --- |
| `status`Type: `String`Default: `null` | Current status of the membership, like `active` or `inactive`. |
| `type`Type: `String`Default: `null` | Type of the membership, used to categorize the user-channel relationship. |
| `custom`Type: `CustomObject`Default: `null` | Any custom properties or metadata associated with the channel-user membership in the form of a JSON. Values must be scalar only; arrays or objects are not supported. [App Context filtering language](https://www.pubnub.com/docs/general/metadata/filtering) doesn’t support filtering by custom properties. |

#### Output

| Type | Description |
| --- | --- |
| `PNFuture<Membership>` | Returned (modified) object containing the membership data. |

### Sample code

Assign the `premium-support` role to `support_agent_15` on the `high-priority-incidents` channel.

```kotlin
// get the list of all user memberships and filter out the right channel
user.getMemberships(filter = "channel.id == 'high-priority-incidents'").async {
    it.onSuccess { membershipsResponse ->
        membershipsResponse
            .memberships
            .firstOrNull()
            // add custom metadata to the user membership
            ?.update(mapOf("role" to "premium-support"))?.async { membership ->
            // ...
        }
    }.onFailure {
        // handle failure
    }
}
```