# Updating a Channel

There are two ways to update a channel using the Stream API - a partial or full update. A partial update will retain any custom key-value data, whereas a complete update is going to remove any that are unspecified in the API request.

### Partial Update

A partial update can be used to set and unset specific fields when it is necessary to retain additional custom data fields on the object. AKA a patch style update.

<codetabs>

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

```kotlin
// Here's a channel with some custom field data that might be useful
val channelClient = client.channel(channelType = "messaging", channelId = "general")

channelClient.create(
  memberIds = listOf("thierry", "tomasso"),
  extraData = mapOf(
    "source" to "user",
    "source_detail" to mapOf("user_id" to 123),
    "channel_detail" to mapOf(
      "topic" to "Plants and Animals",
      "rating" to "pg"
    )
  )
).execute()

// let's change the source of this channel
channelClient.updatePartial(set = mapOf("source" to "system")).execute()

// since it's system generated we no longer need source_detail
channelClient.updatePartial(unset = listOf("source_detail")).execute()

// and finally update one of the nested fields in the channel_detail
channelClient.updatePartial(set = mapOf("channel_detail.topic" to "Nature")).execute()

// and maybe we decide we no longer need a rating
channelClient.updatePartial(unset = listOf("channel_detail.rating")).execute()
```

</codetabs-item>

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

```js
// Here's a channel with some custom field data that might be useful
const channel = client.channel(type, id, {
  source: "user",
  source_detail: { user_id: 123 },
  channel_detail: { topic: "Plants and Animals", rating: "pg" },
});

// let's change the source of this channel
await channel.updatePartial({ set: { source: "system" } });

// since it's system generated we no longer need source_detail
await channel.updatePartial({ unset: ["source_detail"] });

// and finally update one of the nested fields in the channel_detail
await channel.updatePartial({ set: { "channel_detail.topic": "Nature" } });

// and maybe we decide we no longer need a rating
await channel.updatePartial({ unset: ["channel_detail.rating"] });
```

</codetabs-item>

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

```dart
// Here's a channel with some custom field data that might be useful
var channel = client.channel(type, id: id, extraData: {
 "source": "user",
 "source_detail" :{ "user_id": 123 },
 "channel_detail" :{ "topic": "Plants and Animals", "rating": "pg" }
});

// let's change the source of this channel
await channel.updatePartial(set: { "source": "system" });

// since it's system generated we no longer need source_detail
await channel.updatePartial(unset: ["source_detail"]);

// and finally update one of the nested fields in the channel_detail
await channel.updatePartial(set: { "channel_detail.topic": "Nature" });

// and maybe we decide we no longer need a rating
await channel.updatePartial(unset: ["channel_detail.rating"]);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Here's a channel with some custom field data that might be useful
channel = client.channel(type, id , {
 "source": "user",
 "source_detail":{ "user_id": 123 },
 "channel_detail":{ "topic": "Plants and Animals", "rating": "pg" }
})

# let's change the source of this channel
channel.update_partial(to_set={ "source": "system" });

# since it's system generated we no longer need source_detail
channel.update_partial(to_unset=["source_detail"]);

# and finally update one of the nested fields in the channel_detail
channel.update_partial(to_set={ "channel_detail.topic": "Nature" });

# and maybe we decide we no longer need a rating
channel.update_partial(to_unset=["channel_detail.rating"]);
```

</codetabs-item>

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

```php
// Here's a channel with some custom field data that might be useful
$channel = $client->Channel('messaging', 'thierry-jenny',
['source'=>'user','source_detail'=>['user_id'=>123],
'channel_detail'=>['topic'=>'Plants and Animals', 'rating'=> 'pg'] ]);

// let's change the source of this channel
$response = $channel->updatePartial(['source' => 'system']);

// since it's system generated we no longer need source_detail
$response = $channel->updatePartial(null,['source_detail']);

// and finally update one of the nested fields in the channel_detail
$response = $channel->updatePartial(['source_detail'=> ['topic' => 'Nature']]);

// and maybe we decide we no longer need a rating
$response = $channel->updatePartial(null,['source_detail'=>'topic']);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Create a channel with some custom data
var req = new ChannelGetRequest
{
  Data = new ChannelRequest
  {
    CreatedBy = new UserRequest { Id = createdByUserId },
  },
};

req.Data.SetData("source", "user");
req.Data.SetData("source_detail", new Dictionary<string, object> { { "user_id", 123} });
req.Data.SetData("channel_detail", new Dictionary<string, object>
{
  { "topic", "Plants and Animals"},
  { "rating", "pg" }
});
var channelResp = await channelClient.GetOrCreateAsync("messaging", "general", req);

// Remove channel detail rating, and set a new source
var req = new PartialUpdateChannelRequest
{

  Unset = new List<string> { "channel_detail.rating" },
  Set = new Dictionary<string, object> { { "source", "system" } }
};
await channelClient.PartialUpdateAsync(channelResp.Channel.Type, channelResp.Channel.Id, req);
```

</codetabs-item>

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

```cpp
// Create a channel with some custom field data that might be useful
FChannelProperties Props = FChannelProperties{Type, Id};

// Set extra data using dynamic JSON. You'd more likely want to use statically typed structs.
Props.ExtraData.SetString(TEXT("source"), TEXT("user"));
const TSharedRef<FJsonObject> SourceDetail = MakeShared<FJsonObject>();
SourceDetail->SetNumberField(TEXT("user_id"), 123);
Props.ExtraData.SetJsonValue(TEXT("source_detail"), MakeShared<FJsonValueObject>(SourceDetail));
const TSharedRef<FJsonObject> ChannelDetail = MakeShared<FJsonObject>();
ChannelDetail->SetStringField(TEXT("topic"), TEXT("Plants and Animals"));
ChannelDetail->SetStringField(TEXT("rating"), TEXT("pg"));
Props.ExtraData.SetJsonValue(TEXT("source_detail"), MakeShared<FJsonValueObject>(ChannelDetail));
Client->CreateChannel(
  Props,
  [](UChatChannel* Channel)
  {
    // let's change the source of this channel
    const TSharedRef<FJsonObject> NewSource = MakeShared<FJsonObject>();
    NewSource->SetStringField(TEXT("source"), TEXT("system"));
    Channel->PartialUpdate(NewSource);

    // since it's system generated we no longer need source_detail
    Channel->PartialUpdate({}, {TEXT("source_detail")});

    // and finally update one of the nested fields in the channel_detail
    const TSharedRef<FJsonObject> NewTopic = MakeShared<FJsonObject>();
    NewSource->SetStringField(TEXT("channel_detail.topic"), TEXT("Nature"));
    Channel->PartialUpdate(NewSource);

    // and maybe we decide we no longer need a rating
    Channel->PartialUpdate({}, {TEXT("channel_detail.rating")});
  });
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
resp, err := c.CreateChannel(ctx, "messaging", "general", "thierry", map[string]interface{}{
	"source": "user",
	"source_detail": map[string]interface{}{"user_id": "123"},
	"channel_detail": map[string]interface{}{"topic": "Plants and Animals", "rating": "pg"},
})

channel := resp.Channel

// let's change the source of this channel
channel.PartialUpdate(ctx, PartialUpdate{
	Set: map[string]interface{}{
		"source": "system",
	},
})

// since it's system generated we no longer need source_detail
channel.PartialUpdate(ctx, PartialUpdate{
	Unset: []string{"source_detail"},
})

// and finally update one of the nested fields in the channel_detail
channel.PartialUpdate(ctx, PartialUpdate{
	Set: map[string]interface{}{
		"channel_detail.topic": "Nature",
	},
})

// and maybe we decide we no longer need a rating
channel.PartialUpdate(ctx, PartialUpdate{
	Unset: []string{"channel_detail.rating"},
})
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# require 'stream-chat'

# Here's a channel with some custom field data that might be useful
channel = client.channel(type, id , data: {
 "source" => "user",
 "source_detail" => { "user_id" => 123 },
 "channel_detail" => { "topic" => "Plants and Animals", "rating" => "pg" }
})

# let's change the source of this channel
channel.update_partial({ "source" => "system" });

# since it's system generated we no longer need source_detail
channel.update_partial(nil, ["source_detail"]);

# and finally update one of the nested fields in the channel_detail
channel.update_partial({ "channel_detail.topic" => "Nature" });

# and maybe we decide we no longer need a rating
channel.update_partial(nil, ["channel_detail.rating"]);
```

</codetabs-item>

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

```csharp
public async Task PartialUpdate()
{
  var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");

  var setClanInfo = new ClanData
  {
    MaxMembers = 50,
    Name = "Wild Boards",
    Tags = new List<string>
    {
      "Competitive",
      "Legendary",
    }
  };

  var setFields = new Dictionary<string, object>();

  // Set custom values
  setFields.Add("frags", 5);
  // Set custom arrays
  setFields.Add("items", new[] { "sword", "shield" });
  // Set custom class objects
  setFields.Add("clan_info", setClanInfo);

  // Send data
  await channel.UpdatePartialAsync(setFields);

  // Data is now available via CustomData property
  var frags = channel.CustomData.Get<int>("frags");
  var items = channel.CustomData.Get<List<string>>("items");
  var clanInfo = channel.CustomData.Get<ClanData>("clan_info");
}

// Example class with data that you can assign as Channel custom data
private class ClanData
{
  public int MaxMembers;
  public string Name;
  public List<string> Tags;
}
```

</codetabs-item>

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

```java
// Android SDK

// Here's a channel with some custom field data that might be useful
ChannelClient channelClient = client.channel("messaging", "general");

List<String> members = Arrays.asList("thierry", "tommaso");

Map<String, String> channelDetail = new HashMap<>();
channelDetail.put("topic", "Plants and Animals");
channelDetail.put("rating", "pg");

Map<String, Integer> userId = new HashMap<>();
userId.put("user_id", 123);

Map<String, Object> extraData = new HashMap<>();
extraData.put("source", "user");
extraData.put("source_detail", userId);
extraData.put("channel_detail", channelDetail);

channelClient.create(members, extraData).execute();

// let's change the source of this channel
Map<String, Object> setField = Collections.singletonMap("source", "system");
channelClient.updatePartial(setField, emptyList()).execute();

// since it's system generated we no longer need source_detail
List<String> unsetField = Collections.singletonList("source_detail");
channelClient.updatePartial(emptyMap(), unsetField).execute();

// and finally update one of the nested fields in the channel_detail
Map<String, Object> setNestedField = Collections.singletonMap("channel_detail.topic", "Nature");
channelClient.updatePartial(setNestedField, emptyList()).execute();

// and maybe we decide we no longer need a rating
List<String> unsetNestedField = Collections.singletonList("channel_detail.rating");
channelClient.updatePartial(emptyMap(), unsetNestedField).execute();

// Backend SDK
Channel.partialUpdate("messaging", "general")
  .setValue("source", "system")
  .setValue("channel_detail.topic", "Nature")
  .user(user)
  .unsetValue("source_detail")
  .request()
  .getChannel();
```

</codetabs-item>

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

```swift
channelController.partialChannelUpdate(
    extraData: [
        "source": .string("user"),
        "source_detail": .dictionary(["user_id": .number(123)]),
        "channel_detail": .dictionary([
            "topic": .string("Plants and Animals"),
            "rating": .string("pg")
        ])
    ]
) { error in
    if let error {
        // handle error
    }
}

// let's change the source of this channel
channelController.partialChannelUpdate(unsetProperties: ["source_detail"])

// let's change the source of this channel
channelController.partialChannelUpdate(extraData:["source": "system"])

// since it's system generated we no longer need source_detail
channelController.partialChannelUpdate(unsetProperties: ["source_detail"])

// and finally update one of the nested fields in the channel_detail
channelController.partialChannelUpdate(extraData:["channel_detail.topic": "Nature"])
```

</codetabs-item>

</codetabs>

### Full Update (overwrite)

The `update` function updates all of the channel data. **Any data that is present on the channel and not included in a full update will be deleted.**

<codetabs>

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

```kotlin
val channelClient = client.channel("messaging", "general")

channelClient.update(
  message = Message(
    text = "Thierry changed the channel color to green"
  ),
  extraData = mapOf(
    "name" to "myspecialchannel",
    "color" to "green",
  ),
).enqueue { result ->
  if (result is Result.Success) {
    val channel = result.value
  } else {
    // Handle Result.Failure
  }
}
```

</codetabs-item>

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

```js
const update = await channel.update(
  {
    name: "myspecialchannel",
    color: "green",
  },
  { text: "Thierry changed the channel color to green", user_id: "Thierry" },
);
```

</codetabs-item>

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

```dart
await channel.update({
 "name": "myspecialchannel",
 "color": "green",
}, Message(text: "Thierry changed the channel color to green"));
```

</codetabs-item>

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

```php
$update = $channel->update(
	[
		'name'  => 'myspecialchannel',
		'color'	 => 'green'
	],
	[
		'text' => 'Thierry changed the channel color to green',
		'user_id' => 'thierry'
	]
);
```

</codetabs-item>

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

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

channelController.updateChannel(
    name: "My special channel",
    imageURL: nil,
    team: nil,
    extraData: [
        "name": .string("myspecialchannel"),
        "color": .string("green"),
    ]
) { error in
    if let error {
        // handle error
    }
}
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
channel.update(
  {
    "name": "myspecialchannel",
    "color": "green",
  },
  update_message={
    "text": "Thierry changed the channel color to green",
    "user_id": "Thierry",
  },
)
```

</codetabs-item>

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

```cpp
FAdditionalFields Data;
Data.SetString(TEXT("name"), TEXT("myspecialchannel"));
Data.SetString(TEXT("color"), TEXT("green"));
const FMessage Message{TEXT("Thierry changed the channel color to green")};
Channel->Update(Data, Message);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var updatedChannel = new ChannelUpdateRequest { Data = new ChannelRequest() };
updatedChannel.Data.SetData("name", "myspecialchannel");
updatedChannel.Data.SetData("color", "green");
updatedChannel.Message = new MessageRequest { Text = "Thierry changed the channel color to green", UserId = "thierry" }

await channelClient.UpdateAsync(channel.Type, channel.Id, updatedChannel);
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
channel.Update(ctx, map[string]interface{}{"color": "green"},
 &Message{
 	Text: "Thierry changed the channel color to green",
 	User: &User{ID: "thierry"},
 },
)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
channel.update(
  {
    "name" => "myspecialchannel",
    "color" => "green",
  },
  {
    "text" => "Thierry changed the channel color to green",
    "user_id" => "Thierry",
  },
)
```

</codetabs-item>

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

```csharp
var updateRequest = new StreamUpdateOverwriteChannelRequest
{
  Name = "New name",
  CustomData = new StreamCustomDataRequest
  {
    {"my-custom-int", 12},
    {"my-custom-array", new string[]{"one", "two"}}
  }
};

// This request will have all channel data removed except what is being passed in the request
await channel.UpdateOverwriteAsync(updateRequest);

// You can also pass an instance of channel to the request constructor to have all of the date copied over
// This way you alter only the fields you wish to change
var updateRequest2 = new StreamUpdateOverwriteChannelRequest(channel)
{
  Name = "Brand new name"
};

// This will update only the name because all other data was copied over
await channel.UpdateOverwriteAsync(updateRequest2);
```

</codetabs-item>

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

```java
// Android SDK
ChannelClient channelClient = client.channel("messaging", "general");

Map<String, Object> channelData = new HashMap<>();
channelData.put("name", "myspecialchannel");
channelData.put("color", "green");
Message updateMessage = new Message();
updateMessage.setText("Thierry changed the channel color to green");

channelClient.update(updateMessage, channelData).enqueue(result -> {
  if (result.isSuccess()) {
    Channel channel = result.data();
  } else {
    // Handle result.error()
  }
 });


// Backend SDK
MessageRequestObject msg = MessageRequestObject
  .builder()
    .text("Thierry changed the channel color to green")
  .build();

Channel.update("messaging", "general")
  .message(msg)
  .data(ChannelRequestObject.builder()
   .additionalField("name", "myspecialchannel")
   .additionalField("color", "green")
   .build())
  .request();
```

</codetabs-item>

</codetabs>

#### Request Params

| Name         | Type   | Description                                                                                                                                                                          | Optional |
| ------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| channel data | object | Object with the new channel information. One special field is "frozen". Setting this field to true will freeze the channel. Read more about freezing channels in "Freezing Channels" |          |
| text         | object | Message object allowing you to show a system message in the Channel that something changed.                                                                                          | Yes      |

<admonition type="info">

Updating a channel using these methods cannot be used to add or remove members. For this, you must use specific methods for adding/removing members, more information can be found [here](/chat/docs/<framework>/channel_members/).

</admonition>

### Archiving a channel

A member in a channel can mark the channel as archived. The archival state is
stored for this member, so it doesn't affect anybody else. From an API point of
view, an archived channel is the same as another channel, but the user
interface may render an archived channel in a different way. When a channel is
archived, the current date is recorded and this is returned as `archived_at` in
the response.

When querying channels, the query can specify that archived channels
should be excluded. The query can also specify only archived channels.

<codetabs>

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

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

// Archive the channel
channelClient.archive().enqueue { /* ... */ }

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

// Unarchive the channel
channelClient.unarchive().enqueue { /* ... */ }
```

</codetabs-item>

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

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

// Archive the channel.
await channel.archive();

// Query for channels that are not archived.
const resp = await client.queryChannels({ archived: false });

await channel.unarchive();
```

</codetabs-item>

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

```dart
// Archive the channel.
await channel.archive();

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

await channel.unarchive();
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
ctx := context.Background()

// Get a channel
client.channel("messaging", "general")

// Archive the channel for user amy.
userID := "amy"
channelMemberResp, err := channel.Archive(ctx, userID)

// Query for channels that are archived.
resp, err := client.QueryChannels(ctx, &QueryOption{
		UserID: userID,
		Filter: map[string]interface{}{
			"archived": true,
		},
	})

channelMemberResp, err := channel.Unarchive(ctx, userID)
```

</codetabs-item>

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

```php
// Get a channel
$channel = $client.Channel("messaging", "general")

// Archive the channel for user amy.
$userId = "amy"
$response = $channel->archive($userId);

// Query for channels that are archived.
$response = $client->queryChannels([
    "archived" => true,
], null, [
    "user_id" => $userId
]);

$response = $channel->unarchive($userId);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
// Get a channel
channel = client.channel("messaging", "general")

// Archive the channel for user amy.
user_id = "amy"
response = channel.archive(user_id)

// Query for channels that are archived.
response = client.query_channels({"archived": True }, user_id=user_id)

response = channel.unarchive(user_id)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
// Get a channel
channel = client.channel("messaging", "general")

// Archive the channel for user amy.
user_id = "amy"
response = channel.archive(user_id)

// Query for channels that are archived.
response = client.query_channels({ 'archived': true }, sort: nil, user_id: user_id)

response = channel.unarchive(user_id)
```

</codetabs-item>

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

```java
// Archive the channel for user amy.
Channel.archive(channel.getType(), channel.getId(), "amy").request();

// Query for amy's channels that are archived.
Channel.list()
    .userId("amy")
    .filterCondition(FilterCondition.in("members", "amy"))
    .filterCondition("archived", true)
    .request();

// Unarchive
Channel.unarchive(channel.getType(), channel.getId(), "amy").request();
```

</codetabs-item>

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

```swift
// Controllers

// Archive the channel for the current user.
channelController.archive { error in
    if let error {
        // handle error
    }
}

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

// Unarchive the channel for the current user.
channelController.unarchive { error in
    if let error {
        // handle error
    }
}

// State layer (async-await)

// Archive the channel for the current user.
try await chat.archive()

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

// Unarchive the channel for the current user.
try await chat.unarchive()
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Archive
var archiveResponse = await _channelClient.ArchiveAsync("messaging", "channel-id", "user-id");

// Get the date when the channel got archived by the user
var archivedAt = archiveResponse.ChannelMember.ArchivedAt;

// Get channels that are NOT archived
var unarchivedChannels = await _channelClient.QueryChannelsAsync(new QueryChannelsOptions
{
    Filter = new Dictionary<string, object>
    {
        { "archived", false },
    },
    UserId = "user-id",
});

// Unarchive
var unarchiveResponse = await _channelClient.UnarchiveAsync("messaging", "channel-id", "user-id");
```

</codetabs-item>

</codetabs>

### Pinning a channel

Pinning works very similar to archiving. A client can mark a channel as pinned,
which can be used to render it differently in the UI. When a channel is pinned,
the response contains a `pinned_at` timestamp.

Like archiving, it's possible to query channels with a specific pinned state.
It is also possible to sort channels by pin, such as returning pinned channels
first.

<codetabs>

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

```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 { /* ... */ }
```

</codetabs-item>

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

```js
// 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 resp = await client.queryChannels(
  { members: { $in: ["amy", "ben"] } },
  { pinned_at: -1 },
);

await channel.unpin();
```

</codetabs-item>

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

```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();
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
ctx := context.Background()

// Get a channel
client.channel("messaging", "general")

// Pin the channel for user amy.
userID := "amy"
channelMemberResp, err := channel.Pin(ctx, userID)

// Query for channels that are pinned.
resp, err := client.QueryChannels(ctx, &QueryOption{
		UserID: userID,
		Filter: map[string]interface{}{
			"pinned": true,
		},
	})

// Query for channels for specific members and show pinned first.
resp, err = client.QueryChannels(ctx, &QueryOption{
		UserID: userID,
		Filter: map[string]interface{}{
			"members": map[string]interface{}{
        "$in": []string{"amy", "ben"},
      },
		},
		Sort: []*SortOption{
			{Field: "pinned_at", Direction: -1},
		},
})

channelMemberResp, err := channel.Unpin(ctx, userID)
```

</codetabs-item>

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

```php
// Get a channel
$channel = $client.Channel("messaging", "general")

// Pin the channel for user amy.
$userId = "amy"
$response = $channel->pin($userId);

// Query for channels that are pinned.
$response = $client->queryChannels([
    "pinned" => true,
], null, [
    "user_id" => $userId
]);

// Query for channels for specific members and show pinned first.
$response = $client->queryChannels([
        "members" => [ "$in" => [ "amy", "ben" ] ],
    ],
    [ "pinned_at" => -1 ],
    [ "user_id" => $userId ]
);

$response = $channel->unpin($userId);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
// Get a channel
channel = client.channel("messaging", "general")

// Pin the channel for user amy.
user_id = "amy"
response = channel.pin(user_id)

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

// Query for channels for specific members and show pinned first.
response = client.query_channels(
  { "members": { "$in": [ "amy", "ben" ] } },
  { "pinned_at": -1 },
  user_id=user_id
)

response = channel.unpin(user_id)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
// Get a channel
channel = client.channel("messaging", "general")

// Pin the channel for user amy.
user_id = "amy"
response = channel.pin(user_id)

// Query for channels that are pinned.
response = client.query_channels({ 'pinned': true }, sort: nil, user_id: user_id)

// Query for channels for specific members and show pinned first.
response = client.query_channels(
  { 'members' => { '$in' => [ 'amy', 'ben' ] } },
  sort: { 'pinned_at': -1 },
  user_id: user_id
)

response = channel.unpin(user_id)
```

</codetabs-item>

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

```java
// Pin the channel for user amy.
Channel.pin(channel.getType(), channel.getId(), "amy").request()

// Query for amy's channels that are pinned.
Channel.list()
    .userId("amy")
    .filterCondition(FilterCondition.in("members", "amy"))
    .filterCondition("pinned", true)
    .request();

// Query for channels for specific members and show pinned first.
Channel.list()
    .userId("amy")
    .filterConditions(FilterCondition.in("members", "amy", "ali"))
    .sort(Sort.builder().field("pinned_at").direction(Direction.DESC).build())
    .request();

// Unpin
Channel.unpin(channel.getType(), channel.getId(), "amy").request()
```

</codetabs-item>

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

```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.archive()

// 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()
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Pin
var pinResponse = await _channelClient.PinAsync("messaging", "channel-id", "user-id");

// Get the date when the channel got pinned by the user
var pinnedAt = pinResponse.ChannelMember.PinnedAt;

// Get channels pinned for the user
var pinnedChannels = await _channelClient.QueryChannelsAsync(new QueryChannelsOptions
{
    Filter = new Dictionary<string, object>()
    {
        { "pinned", true },
    },
    UserId = "user-id",
});

// Unpin
var unpinResponse = await _channelClient.UnpinAsync("messaging", "channel-id", "user-id");
```

</codetabs-item>

</codetabs>

### Global archiving or pinning

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

---

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

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/android/channel_update/](https://getstream.io/chat/docs/android/channel_update/).