val channelClient = client.channel(channelType = "messaging", channelId = "general")
channelClient.create(memberIds = emptyList(), extraData = emptyMap()).enqueue { result ->
if (result is Result.Success) {
val newChannel: Channel = result.value
} else {
// Handle Result.Failure
}
}Creating Channels
Channels must be created before users can start chatting. Channel creation can occur either client-side or server-side, depending on your app’s requirements. Client-side creation is ideal for apps where users can freely start conversations (for example, a Slack-style workforce management app). Server-side creation is preferred in apps that require business logic before a chat can begin, such as dating apps where users must match first. To limit channel creation to server-side only, remove Create Channel permissions for your users.
There are two ways to create channels: by specifying a channel ID or by creating distinct channels.
Creating a Channel Using a Channel ID
This approach works best when your app already has a database object that naturally maps to a chat channel. For example, in a Twitch-style live-streaming service, each streamer has a unique ID you can reuse as the channel ID, making it easy to route users to the correct chat. Using explicit IDs keeps channels predictable and easy to reference throughout your application.
const channel = client.channel("messaging", "travel", {
name: "Awesome channel about traveling",
});
// Here, 'travel' will be the channel ID
await channel.create();/// 1: Create a `ChannelId` that represents the channel you want to create.
let channelId = ChannelId(type: .messaging, id: "general")
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let channelController = chatClient.channelController(for: channelId)
/// 3: Call `ChatChannelController.synchronize` to create the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
}final channel = client.channel(
"messaging",
id: "travel",
extraData: {
"name": "Founder Chat",
"image": "http://bit.ly/2O35mws",
"members": ["thierry", "tommaso"],
},
);const channel = client.channel("messaging", "travel", {
name: "Awesome channel about traveling",
created_by_id: "myuserid",
});
await channel.create();# require 'stream-chat'
# Note: 'channel_id' parameter must be named!
channel = client.channel('messaging', channel_id: 'general')
channel.create('jlahey')const FChannelProperties Properties{
TEXT("messaging"), // Type
TEXT("travel"), // Id
};
Client->CreateChannel(
Properties,
[](UChatChannel* Channel)
{
// Channel created
});channel = client.channel("messaging", "travel")
channel.create("myuserid")$channel = $client->Channel("messaging", "general");
$channel->create("thierry");var chanData = new ChannelRequest { CreatedBy = new UserRequest { Id = "thierry" } };
await channelClient.GetOrCreateAsync("messaging", "general", new ChannelGetRequest
{
Data = chanData,
});client.CreateChannel(ctx, "messaging", "general", "tommaso", nil)var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, "my-channel-id");
//Once you get or query a channel it is also added to Client.WatchedChannels list// Android SDK
ChannelClient channelClient = client.channel("messaging", "general");
Map<String, Object> extraData = new HashMap<>();
List<String> memberIds = new LinkedList<>();
channelClient.create(memberIds, extraData)
.enqueue(result -> {
if (result.isSuccess()) {
Channel newChannel = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
ChannelGetResponse channel = Channel.getOrCreate("messaging", "general")
.data(
ChannelRequestObject.builder()
.createdBy(someUser)
.additionalField("custom_field", "custom_value") // Optional custom fields
.build())
.request()Distinct Channels
Distinct channels are ideal when you want a single, unique conversation for a specific set of users. By leaving the channel ID empty and specifying only the channel type and members, Stream automatically generates a channel ID by hashing the list of members (order does not matter). This ensures that the same group of users will always reference the same channel, preventing duplicate conversations.
You cannot add members for channels created this way, but members can be removed.
client.createChannel(
channelType = "messaging",
channelId = "",
memberIds = listOf("thierry", "tomasso"),
extraData = emptyMap()
).enqueue { result ->
if (result is Result.Success) {
val channel = result.value
} else {
// Handle Result.Failure
}
}const channel = client.channel("messaging", {
members: ["thierry", "tommaso"],
});
await channel.create();client.channel("messaging", extraData: {"members": ["thierry", "tommaso"]});/// 1: Use the `ChatClient` to create a `ChatChannelController` with a list of user ids
let channelController = try chatClient.channelController(
createDirectMessageChannelWith: ["thierry", "tomasso"],
extraData: [:]
)
/// 2: Call `ChatChannelController.synchronize` to create the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
}const channel = client.channel("messaging", {
members: ["thierry", "tommaso"],
created_by_id: "myuserid",
});
await channel.create();$conversation = $client->Channel('messaging', 'thierry-jenny', ['members'=>['thierry', 'jenny']]);
$state = $conversation->create('thierry');# Note: 'channel_id' and 'data' parameters must be named!
channel = client.channel(
'messaging',
channel_id: 'thierry-tommaso-1',
data: {
'name' => 'Founder Chat',
'image' => 'http://bit.ly/2O35mws',
'members' => ['thierry', 'tommaso'],
}
)
channel.create('thierry')const FChannelProperties Properties = FChannelProperties{TEXT("messaging")}
.SetMembers({TEXT("thierry"), TEXT("tommaso")});
Client->CreateChannel(
Properties,
[](UChatChannel* Channel)
{
// Channel created
});channel = client.channel("messaging", data=dict(members=["thierry"]))
channel.create("myuserid")$channel = $client->Channel(
"messaging",
null,
["members" => ["thierry", "tommaso"]]
);
$channel->create("thierry");var chanData = new ChannelRequest { CreatedBy = new UserRequest { Id = "thierry" } };
await channelClient.GetOrCreateAsync("messaging", new ChannelGetRequest
{
Data = chanData,
});client.CreateChannel(ctx, "messaging", nil, "tommaso", map[string]interface{}{
"members": []string{"thierry", "tommaso"},
})var filters = new IFieldFilterRule[]
{
UserFilter.Id.EqualsTo("other-user-id")
};
// Find user you want to start a chat with
var users = await Client.QueryUsersAsync(filters);
var otherUser = users.First();
var localUser = Client.LocalUserData.User;
// Start direct channel between 2 users
var channel = await Client.GetOrCreateChannelWithMembersAsync(ChannelType.Messaging, new[] { localUser, otherUser});// Android SDK
ChannelClient channelClient = client.channel("messaging", "");
Map<String, Object> extraData = new HashMap<>();
List<String> memberIds = new LinkedList<>();
memberIds.add("thierry");
memberIds.add("tomasso");
channelClient.create(memberIds, extraData)
.enqueue(result -> {
if (result.isSuccess()) {
Channel newChannel = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
List<ChannelMemberRequestObject> memberList = new ArrayList<>();
testUsersRequestObjects.add(
ChannelMemberRequestObject.builder().user(user1).build());
testUsersRequestObjects.add(
ChannelMemberRequestObject.builder().user(user2).build());
ChannelGetResponse channel = Channel.getOrCreate("messaging", null)
.data(
ChannelRequestObject.builder()
.createdBy(someUser)
.members(memberList)
.build())
.request()When you create a channel using one of the above approaches, you’ll specify the following fields:
| name | type | description | default | optional |
|---|---|---|---|---|
| type | string | The channel type. Default types are livestream, messaging, team, gaming and commerce. You can also create your own types. | - | |
| id | string | The channel id (optional). If you don’t specify an ID the ID will be generated based on the list of members. (max length 64 characters) | - | ✓ |
| channel data | object | Extra data for the channel. Must not exceed 5KB in size. | default | ✓ |
Channel Data
Channel data can include any number of custom fields as long as the total payload stays under 5KB. Some fields are reserved—such as members—and our UI components also use name and image when rendering channel lists and headers. In general, you should store only the data that’s essential to your chat experience and avoid adding fields that change frequently.
| Name | Type | Description |
|---|---|---|
| name | string | The channel name. No special meaning, but by default the UI component will try to render this if the property is present. |
| image | string | The channel image. Again there is no special meaning but by default, the UI component will try to render this if the property is present. |
| members | array | The members participating in this Channel. Note that you don’t need to specify members for a live stream or other public chat. You only need to specify the members if you want to limit access of this chat to these members and subscribe them to future updates. |
| custom_data | various types | Channels can contain up to 5KB of custom data. |
| filter_tags | array of strings | List of tags to categorize and filter channels. Maximum 10 tags per channel, each tag limited to 255 characters. Tags are automatically sorted and deduplicated. See Querying Channels for filtering examples. |
Watching Channels
Once a channel exists—or as it is being created on the client—it can be watched by client devices. Watching a channel subscribes the client’s WebSocket connection to real-time updates, such as new messages, membership changes, and reactions. This allows the SDKs to keep channel state and UI in sync automatically.
If your app lets users navigate to a channel client-side, you should use channel.watch(). This is a get-or-create method: it fetches and watches the channel if it already exists, or creates and watches it if it doesn’t. channel.watch() returns the full channel state—including members, watchers, and messages—so your UI can render immediately.
For loading many channels at once, use client.queryChannels()—this fetches and watches multiple channels in a single call, reducing API traffic.
Note that watching a channel is different from being a channel member. A watcher is a temporary, real-time subscription to updates, while a member is a persistent association with the channel.
val channelClient = client.channel(channelType = "messaging", channelId = "general")
channelClient.watch().enqueue { result ->
if (result is Result.Success) {
val channel: Channel = result.value
} else {
// Handle Result.Failure
}
}const channel = client.channel("messaging", "travel-channel");
const state = await channel.watch();final state = await channel.watch();// Channels are watched automatically when they're synchronized.
/// 1: Create a `ChannelId` that represents the channel you want to watch.
let channelId = ChannelId(type: .messaging, id: "general")
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let channelController = chatClient.channelController(for: channelId)
/// 3: Call `ChatChannelController.synchronize` to watch the channel.
channelController.synchronize { error in
if let error = error {
/// 4: Handle possible errors
print(error)
}
}const FChannelProperties Properties{
TEXT("messaging"), // Type
TEXT("general"), // Id
};
Client->WatchChannel(
Properties,
[](UChatChannel* Channel)
{
// Started watching channel
});var filters = new IFieldFilterRule[]
{
UserFilter.Id.EqualsTo("other-user-id")
};
// Find user you want to start chat with
var users = await Client.QueryUsersAsync(filters);
var otherUser = users.First();
var localUser = Client.LocalUserData.User;
// Get channel by ID
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
// Get channel with users combination
var channelWithUsers = await Client.GetOrCreateChannelWithMembersAsync(ChannelType.Messaging,
new[] { localUser, otherUser });
// Access properties
Debug.Log(channel.Name);
Debug.Log(channel.Members);
// Subscribe to events so you can react to updates
channel.MessageReceived += OnMessageReceived;
channel.MessageUpdated += OnMessageUpdated;
channel.MessageDeleted += OnMessageDeleted;
channel.ReactionAdded += OnReactionAdded;
channel.ReactionUpdated += OnReactionUpdated;
channel.ReactionRemoved += OnReactionRemoved;
// You can also access all currently watched channels via
foreach (var c in Client.WatchedChannels)
{
// Every queried channel is automatically watched and starts receiving updates from the server
}ChannelClient channelClient = client.channel("messaging", "general");
channelClient.watch().enqueue(result -> {
if (result.isSuccess()) {
Channel channel = result.data();
} else {
// Handle result.error()
}
});