# Pinning Channels

Channel members can pin a channel for themselves. This is a per-user setting that does not affect other members.

Pinned channels function identically to regular channels via the API, but your UI can display them separately. When a channel is pinned, the timestamp is recorded and returned as `pinned_at` in the response.

When querying channels, filter by `pinned: true` to retrieve only pinned channels, or `pinned: false` to exclude them. You can also sort by `pinned_at` to display pinned channels first.

## Pin a Channel

<Tabs>

```kotlin label="Kotlin"
// Retrieve ChannelClient
val channelClient = client.channel("messaging", "example")

// Pin the channel
channelClient.pin().enqueue { /* ... */ }

// Query for channels that are pinned
val query = QueryChannelsRequest(
  filter = Filters.eq("pinned", true),
  offset = 0,
  limit = 10,
)
client.queryChannels(query).enqueue { /* ... */ }

// Unpin the channel
channelClient.unpin().enqueue { /* ... */ }
```

```js label="JavaScript"
// Get a channel
const channel = client.channel("messaging", "example");

// Pin the channel
await channel.pin();

// Query for channels that are pinned
const resp = await client.queryChannels({ pinned: true });

// Query for channels for specific members and show pinned first
const pinnedFirst = await client.queryChannels(
  { members: { $in: ["amy", "ben"] } },
  { pinned_at: -1 },
);

// Unpin the channel
await channel.unpin();
```

```dart label="Dart"
// Pin the channel.
await channel.pin();

// Query for channels that are pinned.
final channels = await client.queryChannelsOnline(filter: Filter.equal('pinned', true));

// Query for channels for specific members and show pinned first.
final channels = await client.queryChannelsOnline(
  filter: Filter.in_('members', const ['amy', 'ben']),
  channelStateSort: [
    const SortOption(ChannelSortKey.pinnedAt),
  ],
);

// Unpin the channel
await channel.unpin();
```

```go label="Go"
// Get a channel
channel := client.Chat().Channel("messaging", "general")

// Pin the channel for user amy.
userID := "amy"
channel.UpdateMemberPartial(ctx, &getstream.UpdateMemberPartialRequest{
	UserID: getstream.PtrTo(userID),
	Set:    map[string]any{"pinned": true},
})

// Query for channels that are pinned.
client.Chat().QueryChannels(ctx, &getstream.QueryChannelsRequest{
	UserID:           getstream.PtrTo(userID),
	FilterConditions: map[string]any{"pinned": true},
})

// Query for channels for specific members and show pinned first.
client.Chat().QueryChannels(ctx, &getstream.QueryChannelsRequest{
	UserID: getstream.PtrTo(userID),
	FilterConditions: map[string]any{
		"members": map[string]any{"$in": []string{"amy", "ben"}},
	},
	Sort: []getstream.SortParamRequest{
		{Field: getstream.PtrTo("pinned_at"), Direction: getstream.PtrTo(-1)},
	},
})

// Unpin the channel
channel.UpdateMemberPartial(ctx, &getstream.UpdateMemberPartialRequest{
	UserID: getstream.PtrTo(userID),
	Unset:  []string{"pinned"},
})
```

```php label="Php"
use GetStream\ChatClient;
use GetStream\GeneratedModels as Models;

$client = new ChatClient("{{ api_key }}", "{{ api_secret }}");

// Pin the channel for user amy.
$userId = "amy";
$client->updateMemberPartial("messaging", "general", $userId, new Models\UpdateMemberPartialRequest(
    set: (object)["pinned" => true],
));

// Query for channels that are pinned.
$response = $client->queryChannels(new Models\QueryChannelsRequest(
    filterConditions: (object)["pinned" => true],
    userID: $userId,
));

// Query for channels for specific members and show pinned first.
$response = $client->queryChannels(new Models\QueryChannelsRequest(
    filterConditions: (object)["members" => (object)['$in' => ["amy", "ben"]]],
    sort: [new Models\SortParamRequest(field: "pinned_at", direction: -1)],
    userID: $userId,
));

// Unpin the channel
$client->updateMemberPartial("messaging", "general", $userId, new Models\UpdateMemberPartialRequest(
    set: (object)["pinned" => false],
));
```

```python label="Python"
from getstream.models import SortParamRequest

# Get a channel
channel = client.chat.channel("messaging", "general")

# Pin the channel for user amy
user_id = "amy"
response = channel.update_member_partial(user_id=user_id, set={"pinned": True})

# Query for channels that are pinned
response = client.chat.query_channels(filter_conditions={"pinned": True}, user_id=user_id)

# Query for channels for specific members and show pinned first
response = client.chat.query_channels(
    filter_conditions={"members": {"$in": ["amy", "ben"]}},
    sort=[SortParamRequest(field="pinned_at", direction=-1)],
    user_id=user_id,
)

# Unpin the channel
response = channel.update_member_partial(user_id=user_id, unset=["pinned"])
```

```ruby label="Ruby"
require 'getstream_ruby'

Models = GetStream::Generated::Models

# Pin the channel for user amy
user_id = "amy"
response = client.chat.update_member_partial("messaging", "general", Models::UpdateMemberPartialRequest.new(
  set: { 'pinned' => true }
), user_id)

# Query for channels that are pinned
response = client.chat.query_channels(Models::QueryChannelsRequest.new(
  filter_conditions: { 'pinned' => true },
  user_id: user_id
))

# Query for channels for specific members and show pinned first
response = client.chat.query_channels(Models::QueryChannelsRequest.new(
  filter_conditions: { 'members' => { '$in' => ['amy', 'ben'] } },
  sort: [Models::SortParamRequest.new(field: 'pinned_at', direction: -1)],
  user_id: user_id
))

# Unpin the channel
response = client.chat.update_member_partial("messaging", "general", Models::UpdateMemberPartialRequest.new(
  unset: ['pinned']
), user_id)
```

```java label="Java"
// Pin the channel for user amy.
chat.updateMemberPartial(channel.getType(), channel.getId(),
    UpdateMemberPartialRequest.builder()
        .UserID("amy")
        .set(Map.of("pinned", true))
        .build()).execute();

// Query for amy's channels that are pinned.
chat.queryChannels(QueryChannelsRequest.builder()
    .userID("amy")
    .filterConditions(Map.of(
        "members", Map.of("$in", List.of("amy")),
        "pinned", true))
    .build()).execute();

// Query for channels for specific members and show pinned first.
chat.queryChannels(QueryChannelsRequest.builder()
    .userID("amy")
    .filterConditions(Map.of(
        "members", Map.of("$in", List.of("amy", "ali"))))
    .sort(List.of(SortParamRequest.builder()
        .field("pinned_at").direction(-1).build()))
    .build()).execute();

// Unpin
chat.updateMemberPartial(channel.getType(), channel.getId(),
    UpdateMemberPartialRequest.builder()
        .UserID("amy")
        .unset(List.of("pinned"))
        .build()).execute();
```

```swift label="Swift"
// Controllers

// Pin the channel for the current user.
channelController.pin { error in
    if let error {
        // handle error
    }
}

// Query all the pinned channels.
let channelListController = chatClient.channelListController(
    query: ChannelListQuery(
        filter: .and([
            .containMembers(userIds: [currentUserId]),
            .equal(.pinned, to: true)
        ])
    )
)
channelListController.synchronize { error in
    if let error {
        // handle error
    } else {
        let pinnedChannels = channelListController.channels
    }
}

// Unpin the channel for the current user.
channelController.unpin { error in
    if let error {
        // handle error
    }
}

// State layer (async-await)

// Pin the channel for the current user
try await chat.pin()

// Query all the pinned channels.
let channelList = chatClient.makeChannelList(
    with: ChannelListQuery(
        filter: .and([
            .containMembers(userIds: [currentUserId]),
            .equal(.pinned, to: true)
        ])
    )
)
try await channelList.get()
let pinnedChannels = channelList.state.channels

// Unpin the channel for the current user.
try await chat.unpin()
```

```csharp label="C#"
using GetStream;
using GetStream.Models;

var client = new StreamClient("{{ api_key }}", "{{ api_secret }}");
var chat = new ChatClient(client);

var channelId = "channel-id";
var memberId = "user-id";

// Pin the channel for user
await client.MakeRequestAsync<UpdateMemberPartialRequest, UpdateMemberPartialResponse>(
    "PATCH",
    "/api/v2/chat/channels/{type}/{id}/member",
    new Dictionary<string, string> { ["user_id"] = memberId },
    new UpdateMemberPartialRequest
    {
        Set = new Dictionary<string, object> { ["pinned"] = true }
    },
    new Dictionary<string, string> { ["type"] = "messaging", ["id"] = channelId });

// Unpin the channel for user
await client.MakeRequestAsync<UpdateMemberPartialRequest, UpdateMemberPartialResponse>(
    "PATCH",
    "/api/v2/chat/channels/{type}/{id}/member",
    new Dictionary<string, string> { ["user_id"] = memberId },
    new UpdateMemberPartialRequest
    {
        Set = new Dictionary<string, object> { ["pinned"] = false }
    },
    new Dictionary<string, string> { ["type"] = "messaging", ["id"] = channelId });
```

</Tabs>

## Global Pinning

Channels are pinned for a specific member. If the channel should instead be pinned for all users, this can be stored as custom data in the channel itself. The value cannot collide with existing fields, so use a value such as `globally_pinned: true`.


---

This page was last updated at 2026-05-22T16:32:18.097Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/php/pinning-channels/](https://getstream.io/chat/docs/php/pinning-channels/).