val channelClient = client.channel("messaging", "general")
// Add members with ids "thierry" and "josh"
channelClient.addMembers(listOf("thierry", "josh")).enqueue { result ->
if (result is Result.Success) {
val channel: Channel = result.value
} else {
// Handle Result.Failure
}
}
// Add member "thierry" with custom data with key: "code_name" and value "007"
val params = AddMembersParams(
members = listOf(
MemberData(userId = "thierry", extraData = mapOf("code_name" to "007")),
),
)
channelClient.addMembers(params).enqueue { result ->
if (result is Result.Success) {
val channel: Channel = result.value
} else {
// Handle Result.Failure
}
}Channel Members
Channel members are users who have been added to a channel and can participate in conversations. This page covers how to manage channel membership, including adding and removing members, controlling message history visibility, and managing member roles.
Adding and Removing Members
Adding Members
Using the addMembers() method adds the given users as members to a channel.
await channel.addMembers(["thierry", "josh"]);
// Add user to the channel with role set
await channel.addMembers([
{ user_id: "james_bond", channel_role: "channel_moderator" },
]);
// Add new channel member with custom data
await channel.addMembers([{ user_id: "james_bond", code_name: "007" }]);await channel.addMembers(["thierry", "josh"]);$channel->addMembers(['thierry', 'jenny']);import StreamChat
let controller = chatClient.channelController(for: .init(type: .messaging, id: "general"))
controller.addMembers(userIds: ["thierry", "josh"])err := channel.AddMembers([]string{"thierry"}, nil, nil)Channel->AddMembers({TEXT("thierry"), TEXT("josh")});channel.add_members(["thierry", "josh"])await channelClient.AddMembersAsync("channel-type", "channel-id", "thierry", "josh");channel.add_members(["thierry", "josh"])// Android SDK
ChannelClient channelClient = client.channel("messaging", "general");
// Add members with ids "thierry" and "josh"
channelClient.addMembers(Arrays.asList("thierry", "josh"), null).enqueue(result -> {
if (result.isSuccess()) {
Channel channel = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
Channel.update("messaging", "general")
.addMembers(Arrays.asList("thierry", "josh"))
.request();var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
// Add IStreamUser collection as members
await channel.AddMembersAsync(users);
// Or add by ID
await channel.AddMembersAsync("some-user-id-1", "some-user-id-2");Note: You can only add/remove up to 100 members at once.
Members can also be added when creating a channel:
val channelClient = client.channel("messaging", "general")
// Add members during channel creation
channelClient.create(
memberIds = listOf("james_bond", "alec_trevelyan", "bill_fairbanks"),
extraData = emptyMap(),
).enqueue()
// Add members with custom extra data during channel creation
val params = CreateChannelParams(
members = listOf(
MemberData(userId = "james_bond", extraData = mapOf("code_name" to "007")),
MemberData(userId = "alec_trevelyan", extraData = mapOf("code_name" to "006")),
),
extraData = emptyMap(),
)
channelClient.create(params).enqueue()const channel = client.channel("messaging", randomID, {
members: [
{ user_id: "james_bond", code_name: "007" },
{ user_id: "alec_trevelyan", code_name: "006" },
],
});
await channel.create();let channelId = ChannelId(type: .messaging, id: "general")
let channelController = try chatClient.channelController(
createChannelWithId: channelId,
members: ["thierry", "tommaso"]
)
channelController.synchronize { error in
if let error = error {
print(error)
}
}// Members can be added by passing an array of user IDs
var response = await _channelClient.GetOrCreateAsync("messaging", "my-channel-id", createdBy: "user-1",
members: new[] { "user-2", "user-3" });
var channel = response.Channel;Removing Members
Using the removeMembers() method removes the given users from the channel.
// Remove member with id "tommaso"
channelClient.removeMembers(listOf("tommaso")).enqueue { result ->
if (result is Result.Success) {
val channel: Channel = result.value
} else {
// Handle Result.Failure
}
}await channel.removeMembers(["tommaso"]);await channel.removeMembers(["tommaso"]);$channel->removeMembers(['thierry', 'jenny']);controller.removeMembers(userIds: ["tommaso"])Channel->RemoveMembers({TEXT("tommaso")});channel.remove_members(["tommaso"])await channelClient.RemoveMembersAsync("channel-type", "channel-id", new[] { "thierry", "josh" });channel.remove_members(["tommaso"])// Android SDK
channelClient.removeMembers(Arrays.asList("tommaso"), null).enqueue(result -> {
if (result.isSuccess()) {
Channel channel = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
Channel.update("messaging", "general")
.removeMember("tommaso")
.request();// Access channel members via channel.Members
var member = channel.Members.First();
await channel.RemoveMembersAsync(member);
// Remove by user ID
await channel.RemoveMembersAsync("some-user-id-1", "some-user-id-2");resp, err := ch.RemoveMembers(ctx, []string{"my_user_id"})Leaving a Channel
Users can leave a channel without moderator-level permissions. Ensure channel members have the Leave Own Channel permission enabled.
channelClient.removeMembers(listOf("my_user_id")).enqueue()// Remove own channel membership
await channel.removeMembers(["my_user_id"]);channelController.removeMembers(userIds: ["john"]) { error in
// …
}Channel->RemoveMembers({TEXT("my-user-id")});await channel.RemoveMembersAsync(member);You can familiarize yourself with all permissions in the Permissions section.
Hide History
When members join a channel, you can specify whether they have access to the channel’s message history. By default, new members can see the history. Set hide_history to true to hide it for new members.
// Add members by their IDs with hideHistory=true
channelClient.addMembers(
memberIds = listOf("thierry"),
hideHistory = true,
).enqueue()
// Add members by their IDs with hideHistory=true and custom extra data
val params = AddMembersParams(
members = listOf(
MemberData(userId = "thierry", extraData = mapOf("new_member" to true)),
),
hideHistory = true,
)
channelClient.addMembers(params).enqueue()await channel.addMembers(["thierry"], undefined, { hide_history: true });err := channel.AddMembers([]string{"thierry"}, nil, stream_chat.AddMembersWithHideHistory())channel.add_members(["thierry"], hide_history=True)$channel->addMembers(["thierry"], ["hide_history" => true]);await channelClient.AddMembersAsync("channel-type", "channel-id", new[] {"thierry"}, null, new AddMemberOptions { HideHistory = true })channel.add_members(["tommaso", "josh"], hide_history: true)// Backend SDK
Channel.update("channel-type", "channel-type")
.addMember("thierry")
.hideHistory(true)
.request();await channel.AddMembersAsync(users, hideHistory: true);channelController.addMembers(
userIds: ["thierry"],
hideHistory: true
) { error in
// …
}Hide History Before a Specific Date
Alternatively, hide_history_before can be used to hide any history before a given timestamp while giving members access to later messages. The value must be a timestamp in the past in RFC 3339 format. If both parameters are defined, hide_history_before takes precedence over hide_history.
val cutoff = Date()
cutoff.time -= 7.days.inWholeMilliseconds
channelClient
.addMembers(memberIds = listOf("thierry"), hideHistoryBefore = cutoff)
.enqueue()const cutoff = new Date();
cutoff.setDate(date.getDate() - 7); // Last 7 days
await channel.addMembers(["thierry"], undefined, {
hide_history_before: cutoff.toISOString(),
});cutoff := time.Now().Add(-7 * 24 * time.Hour)
err := channel.AddMembers([]string{"thierry"}, nil, stream_chat.AddMembersWithHideHistoryBefore(cutoff))from datetime import datetime, timedelta, timezone
cutoff = datetime.now(timezone.utc) - timedelta(days=7) # Last 7 days
channel.add_members(["thierry"], hide_history_before=cutoff)$cutoff = new DateTime('-7 days'); // Last 7 days
$channel->addMembers(["thierry"], ["hide_history_before" => $cutoff]);var cutoff = DateTimeOffset.UtcNow.AddDays(-7); // Last 7 days
await channelClient.AddMembersAsync("channel-type", "channel-id", new[] {"thierry"}, null, new AddMemberOptions { HideHistoryBefore = cutoff })cutoff = DateTime.now - 7 # Last 7 days
channel.add_members(["thierry"], hide_history_before: cutoff)// Backend SDK
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -7);
Date cutoff = calendar.getTime();
Channel.update("channel-type", "channel-id")
.addMember("thierry")
.hideHistoryBefore(cutoff)
.request();final cutoff = DateTime.now().subtract(Duration(days: 7)); // Last 7 days
await channel.addMembers(
["thierry"],
hideHistoryBefore: cutoff,
);System Message Parameter
You can optionally include a message object when adding or removing members that client-side SDKs will use to display a system message. This works for both adding and removing members.
val channelClient = client.channel("messaging", "general")
// Add members with a system message
channelClient.addMembers(
listOf("thierry", "josh"),
Message(text = "Thierry and Josh joined this channel."),
).enqueue()
// Add members with custom extra data and a system message
val params = AddMembersParams(
members = listOf(
MemberData(userId = "thierry", extraData = mapOf("new_member" to true)),
MemberData(userId = "josh", extraData = mapOf("new_member" to true)),
),
systemMessage = Message(text = "Thierry and Josh joined this channel."),
)
channelClient.addMembers(params).enqueue()
// Remove member with a system message
channelClient.removeMembers(
listOf("tommaso"),
Message(text = "Tommaso was removed from this channel."),
).enqueue()// Using client-side client
await channel.addMembers(["tommaso"], { text: "Tommaso joined the channel." });
// Using server-side client, you need to specify the sender user_id
await channel.addMembers(["tommaso"], {
text: "Tommaso joined the channel.",
user_id: "tommaso",
});err := channel.AddMembers([]string{"tommaso"}, &Message{Text: "Tommaso joined the channel.", User: &User{ID: "tommaso"}}, nil)channel.add_members(["tommaso", "josh"], { "text": 'Tommaso joined the channel.', "user_id": 'tommaso' })$channel->addMembers(['tommaso'], ["message" =>
["text" => "Tommaso joined the channel.", "user_id" => "tommaso"]
]);var msg = new MessageRequest { Text: "Tommaso joined the channel", UserId: "tommaso" };
await channelClient.AddMembersAsync("channel-type", "channel-id", new[] {"tommaso"}, msg, null);channel.add_members(["tommaso", "josh"], message: { "text" => 'Tommaso joined the channel.', "user_id" => 'tommaso' })// Android SDK
Message addMemberSystemMessage = new Message();
addMemberSystemMessage.setText("Thierry and Josh were added to this channel");
channelClient.addMembers(Arrays.asList("thierry", "josh"), addMemberSystemMessage).enqueue(result -> {
if (result.isSuccess()) {
Channel channel = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
MessageRequestObject msg = MessageRequestObject
.builder()
.text("Thierry and Josh were added to this channel")
.build();
Channel.update("messaging", "general")
.addMembers(Arrays.asList("thierry", "josh"))
.message(msg)
.request();Channel->AddMembers({TEXT("tommaso")}, FMessage{TEXT("Tommaso joined the channel.")});await channel.AddMembersAsync(users, hideHistory: default, new StreamMessageRequest
{
Text = "John has joined the channel"
});channelController.addMembers(
userIds: ["tommaso"],
message: "Tommaso joined the channel"
) { error in
// …
}Adding and Removing Moderators
Using the addModerators() method adds the given users as moderators (or updates their role to moderator if already members), while demoteModerators() removes the moderator status.
Add Moderators
await channel.addModerators(["thierry", "josh"]);channel.add_moderators(["thierry", "josh"])channel.add_moderators(["thierry", "josh"])$channel->addModerators(['thierry', 'jenny']);// Backend SDK
Channel.update("channel-type", "channel-type").addModerator("thierry").addModerator("josh").request();await channelClient.AddModeratorsAsync("channel-type", "channel-type", new[] { "thierry", "josh" });newModerators := []string{"bob", "sue"}
err = channel.AddModerators("thierry", "josh")
err = channel.AddModerators(newModerators...)Remove Moderators
await channel.demoteModerators(["tommaso"]);channel.demote_moderators(["tommaso"])channel.demote_moderators(["tommaso"])$channel->demoteModerators(['thierry', 'jenny']);// Backend SDK
Channel.update("channel-type", "channel-type").demoteModerator("tommaso").request();await channelClient.DemoteModeratorsAsync("channel-type", "channel-type", new[] { "tommaso" });err = channel.DemoteModerators(newModerators...)These operations can only be performed server-side, and a maximum of 100 moderators can be added or removed at once.
Member Custom Data
Custom data can be added at the channel member level. This is useful for storing member-specific information that is separate from user-level data. Ensure custom data does not exceed 5KB.
Adding Custom Data
// Add custom data while creating the channel
const channel = client.channel("messaging", randomID, {
members: [
{ user_id: "userid1", key1: "value1" },
{ user_id: "userid2", key1: "value1" },
{ user_id: "userid3", key2: "value2" },
],
});
// Add custom data with addMembers method
await channel.addMembers([{ user_id: "userid1", key1: "value1" }]);channelController.addMembers([
MemberInfo(userId: "userid1", extraData: ["key1": .string("value1")]),
MemberInfo(userId: "userid2", extraData: ["key2": .string("value2")]),
MemberInfo(userId: "userid3", extraData: ["key3": .string("value3")])
])// Add custom data while creating the channel
val params = CreateChannelParams(
members = listOf(
MemberData(userId = "userid1", extraData = mapOf("key1" to "value1")),
MemberData(userId = "userid2", extraData = mapOf("key2" to "value2")),
MemberData(userId = "userid3", extraData = mapOf("key3" to "value3")),
),
extraData = emptyMap(),
)
channelClient.create(params).enqueue()
// Add custom data with addMembers method
val params = AddMembersParams(
members = listOf(
MemberData(userId = "userid1", extraData = mapOf("key1" to "value1")),
),
)
channelClient.addMembers(params).enqueue()await _channelClient.AddMembersAsync("messaging", "my-channel-id", new[] { "user-2" });
var partialRequest = new ChannelMemberPartialRequest
{
UserId = "user-2",
Set = new Dictionary<string, object>
{
{ "hat", "blue" }, // Channel member custom data is separate from user custom data
},
};
await _channelClient.UpdateMemberPartialAsync("messaging", "my-channel-id", partialRequest);Updating Member Data
Channel members can be partially updated. Only custom data and channel roles are eligible for modification. You can set or unset fields, either separately or in the same call.
// Set some fields
await channel.updateMemberPartial(
{
set: {
key1: "new value 1",
key2: "new value 2",
channel_role: "channel_moderator",
},
},
{ userId: "jane" },
);
// Unset some fields
await channel.updateMemberPartial(
{
unset: ["key1", "key2"],
},
{ userId: "jane" },
);
// Set and unset in the same call
await channel.updateMemberPartial(
{
set: {
key1: "new value 1",
key2: "new value 2",
},
unset: ["key3"],
},
{ userId: "jane" },
);// Set some fields
let memberController = ChatClient.shared.memberController(
userId: someUserId,
in: someChannelId
)
memberController.partialUpdate(extraData: [
"key1": .string("value1"),
"key2": .string("value2")
])
// Unset some fields
memberController.partialUpdate(extraData: nil, unsetProperties: ["key1", "key2"])
// Set and unset in the same call
memberController.partialUpdate(
extraData: [
"key1": .string("value1"),
"key2": .string("value2"),
],
unsetProperties: ["key3"]
)// Set some fields
member, err := ch.PartialUpdateMember(ctx, members[0], PartialUpdate{
Set: map[string]interface{}{
"color": "red",
},
})
// Unset some fields
member, err := ch.PartialUpdateMember(ctx, members[0], PartialUpdate{
Unset: []string{"age"},
})
// Set and unset in the same call
member, err := ch.PartialUpdateMember(ctx, members[0], PartialUpdate{
Set: map[string]interface{}{
"color": "red",
},
Unset: []string{"age"},
})$userId = "amy";
// Set some fields
$response = $this->channel->updateMemberPartial($userId, ["hat" => "blue"]);
// Unset some fields
$response = $this->channel->updateMemberPartial($userId, null, ["hat"]);
// Set and unset in the same call
$response = $this->channel->updateMemberPartial($userId, ["hat" => "blue"], ["hat"]);user_id = "amy"
# Set some fields
response = channel.update_member_partial(user_id, to_set={"hat": "blue"})
# Unset some fields
response = channel.update_member_partial(user_id, to_set=None, to_unset=["hat"])
# Set and unset in the same call
response = channel.update_member_partial(user_id, to_set={"color": "red"}, to_unset=["hat"])user_id = "amy"
# Set some fields
response = channel.update_member_partial(user_id, set: { 'color' => 'red' })
# Unset some fields
response = channel.update_member_partial(user_id, set: nil, unset: ['hat'])
# Set and unset in the same call
response = channel.update_member_partial(user_id, set: { 'color' => 'red' }, unset: ['hat'])// Set some fields
Channel.updateMemberPartial(channel.getType(), channel.getId(), "user-1")
.setValue("custom_key", "custom_value")
.setValue("channel_role", "channel_moderator")
.request();
// Unset some fields
Channel.updateMemberPartial(channel.getType(), channel.getId(), "user-1")
.unsetValue("custom_key")
.request();
// Set and unset in the same call
Channel.updateMemberPartial(channel.getType(), channel.getId(), "user-1")
.setValue("color", "red")
.unsetValue("age")
.request();// Set some fields
var memberResponse = await _channelClient.UpdateMemberPartialAsync("messaging", "my-channel-id",
new ChannelMemberPartialRequest
{
UserId = "user-2",
Set = new Dictionary<string, object>
{
{ "hat", "blue" },
{ "score", 1000 },
},
});
// Unset some fields
var memberResponse2 = await _channelClient.UpdateMemberPartialAsync("messaging", "my-channel-id",
new ChannelMemberPartialRequest
{
UserId = "user-2",
Unset = new[] { "hat", "score" },
});
// Set and unset in a single request
var memberResponse3 = await _channelClient.UpdateMemberPartialAsync("messaging", "my-channel-id",
new ChannelMemberPartialRequest
{
UserId = "user-2",
Set = new Dictionary<string, object>
{
{ "hat", "blue" },
},
Unset = new[] { "score" },
});// Set some fields
channelClient.partialUpdateMember(
userId = "userid1",
set = mapOf(
"key1" to "new value 1",
"key2" to "new value 2",
),
).enqueue()
// Unset some fields
channelClient.partialUpdateMember(
userId = "userid1",
unset = listOf("key1", "key2"),
).enqueue()
// Set and unset in the same call
channelClient.partialUpdateMember(
userId = "userid1",
set = mapOf(
"key1" to "new value 1",
"key2" to "new value 2",
),
unset = listOf("key3"),
).enqueue()