val channelClient = client.channel("messaging", "general")
// Add reaction 'like' with a custom field
val reaction = Reaction(
messageId = "message-id",
type = "like",
score = 1,
extraData = mutableMapOf("customField" to 1),
)
channelClient.sendReaction(reaction).enqueue { result ->
if (result is Result.Success) {
val sentReaction: Reaction = result.value
} else {
// Handle Result.Failure
}
}
// Add reaction 'like' and replace all other reactions of this user by it
channelClient.sendReaction(reaction, enforceUnique = true).enqueue { result ->
if (result is Result.Success) {
val sentReaction: Reaction = result.value
} else {
// Handle Result.Failure
}
}Reactions
The Stream Chat SDK has built-in support for user reactions. Some common examples are likes, comments, loves, etc. The reactions are also customizable, so you can use any type of reaction your application requires.

Sending a Reaction
// Add reaction 'love' with custom field, using emoji
const reaction = await channel.sendReaction(messageID, {
type: "love",
myCustomField: "💙",
});
// Add reaction 'love' from the server side
const reaction = await channel.sendReaction(messageID, {
type: "love",
user_id: userid,
});
// Add reaction 'like' and replace all other reactions of this user by it
const reaction = await channel.sendReaction(
messageID,
{ type: "love", user_id: userid },
{ enforce_unique: true },
);let channelId = ChannelId(type: .messaging, id: "general")
let messageId: MessageId = "message-id"
let messageController = chatClient.messageController(cid: channelId, messageId: messageId)
messageController.addReaction("like") { error in
print(error ?? "message liked")
}$response = $channel->sendReaction('message-id', ['type'=>'love','myCustomField'=>123], $userId);await channel.sendReaction("messageID", "like", extraData: {"customField": 1});channel.send_reaction(message_id, {"type": "love", "my_custom_field": 123}, user_id)reaction := &stream_chat.Reaction{
Type: "love",
ExtraData: map[string]interface{}{"my_custom_field": 123},
}
msg, err := channel.SendReaction(reaction, msgID, userID)const FReaction Reaction = Channel->SendReaction(Message, TEXT("love"));# require 'stream-chat'
channel.send_reaction(message_id, {type: "love", my_custom_field: 123}, user_id)await reactionClient.SendReactionAsync(message.Id, "love", user.Id);// Send simple reaction with a score of 1
await message.SendReactionAsync("like");
// Send reaction with a custom score value
await message.SendReactionAsync("clap", 10);
// Send reaction with a custom score value
await message.SendReactionAsync("clap", 10);
// Send reaction and replace all previous reactions (if any) from this user
await message.SendReactionAsync("love", enforceUnique: true);Below you can find all the parameters for sending a reaction:
| name | type | description | default | optional |
|---|---|---|---|---|
| message_id | string | ID of the message to react to | ||
| reaction.type | string | Type of the reaction. User could have only 1 reaction of each type per message | ||
| reaction.score | integer | Score of the reaction for cumulative reactions (see example below) | 1 | ✓ |
| user_id | string | User ID for server side calls | ✓ | |
| enforce_unique | boolean | If set to true, new reaction will replace all reactions the user has (if any) on this message | false | ✓ |
| skip_push | boolean | Do not send a push notification | false | ✓ |
| emoji_code | string | Accepts an unicode which is used by the backend to display the emoji in push notification | ✓ |
Custom data for reactions is limited to 1KB.
Cumulative Reactions (Clap)
You can use the Reactions API to build something similar to Medium’s clap reactions. If you are not familiar with this, Medium allows you to clap articles more than once and shows the sum of all claps from all users.

To do this, you only need to include a score for the reaction (ie. user X clapped 25 times) and the API will return the sum of all reaction scores as well as each user’s individual scores (ie. clapped 475 times, user Y clapped 14 times).
val reaction = Reaction(messageId = "message-id", type = "clap", score = 5)
channelClient.sendReaction(reaction).enqueue { /* ... */ }// user claps 5 times on a message
await channel.sendReaction(messageID, {
type: "clap",
score: 5,
});
// same user claps 20 times more
await channel.sendReaction(messageID, {
type: "clap",
score: 25,
});// user claps 5 times on a message
await channel.sendReaction("messageID", "like", score: 5);
// same user claps 20 times more
await channel.sendReaction("messageID", "like", score: 25);# user claps 5 times on a message
channel.send_reaction(message_id, {"type": "clap", "score": 5}, user_id)
# same user claps 20 times more
channel.send_reaction(message_id, {"type": "clap", "score": 25}, user_id)// user claps 5 times on a message
$channel->sendReaction('message-id', ['type'=>'clap', 'score'=>5], $userId);
// same user claps 20 times more
$channel->sendReaction('message-id', ['type'=>'clap', 'score'=>25], $userId);_, err = channel.SendReaction(&stream_chat.Reaction{
Type: "clap", ExtraData: map[string]interface{}{"score": 25},
}, msgID, userID)messageController.addReaction("clap", score: 2) { error in
print(error ?? "message clapped twice")
}// user claps 5 times on a message
Channel->SendReaction(Message, TEXT("like"), 5);
// same user claps 20 times more
Channel->SendReaction(Message, TEXT("like"), 20);# user claps 5 times on a message
channel.send_reaction(message_id, {type: "clap", score: 5}, user_id)
# same user claps 20 times more
channel.send_reaction(message_id, {type: "clap", score: 25}, user_id)// user claps 5 times on a message
var reaction = new ReactionRequest { Type = "clap", UserId = user.Id, Score = 5 };
await reactionClient.SendReactionAsync(message.Id, reaction);
// same user claps 20 times more
var reaction = new ReactionRequest { Type = "clap", UserId = user.Id, Score = 25 };
await reactionClient.SendReactionAsync(message.Id, reaction);await message.SendReactionAsync("clap", score: 3);// Android SDK
Reaction reaction = new Reaction.Builder()
.withMessageId("message-id")
.withType("like")
.withScore(5)
.build();
boolean enforceUnique = false;
channelClient.sendReaction(reaction, enforceUnique).enqueue(result -> { /* ... */ });
// Backend SDK
// Add reaction 'like' and replace all other reactions of this user by it
Reaction.send(messageId)
.enforceUnique(true)
.reaction(ReactionRequestObject.builder().type("like").score(5).userId(userId).build())
.request();Removing a Reaction
channelClient.deleteReaction(
messageId = "message-id",
reactionType = "like",
).enqueue { result ->
if (result is Result.Success) {
val message: Message = result.value
} else {
// Handle Result.Failure
}
}await channel.deleteReaction(messageID, "love");messageController.deleteReaction("like") { error in
print(error ?? "like removed")
}$response = $channel->deleteReaction('message-id','love', $userId);await channel.deleteReaction("messageID", "like");channel.delete_reaction(message_id, "love", user_id)_, err := channel.DeleteReaction(msgID, "love", userID)Channel->DeleteReaction(Message, Reaction);channel.delete_reaction(message_id, "love", user_id)await reactionClient.DeleteReactionAsync(message.Id, "love", user.Id);await message.DeleteReactionAsync("like");// Android SDK
String reactionType = "like";
channelClient.deleteReaction("message-id", reactionType).enqueue(result -> {
if (result.isSuccess()) {
Message message = result.getOrNull();
} else {
// Handle result.error()
}
});
// Backend SDK
Reaction.delete(message.getId(), reactionType)
.userId(user.getId())
.request());Fetching Reactions
The message object will contain the most recent reactions of a message. But if you need to display all the reactions of a message, you can do so by fetching all the reactions.
// Get the first 10 reactions
channelClient.getReactions(
messageId = "message-id",
offset = 0,
limit = 10,
).enqueue { result ->
if (result is Result.Success) {
val reactions: List<Reaction> = result.value
} else {
// Handle Result.Failure
}
}
// Get the second 10 reactions
channelClient.getReactions(
messageId = "message-id",
offset = 10,
limit = 10,
).enqueue { /* ... */ }// get the first 10 reactions
const response = await channel.getReactions(messageID, { limit: 10 });
// get 3 reactions past the first 10
const response = await channel.getReactions(messageID, {
limit: 3,
offset: 10,
});// Load 10 first reactions
messageController.loadReactions(limit: 10, offset: 0) { result in
let loadedReactions = messageController.reactions
}
// Load 10 more reactions
messageController.loadNextReactions(limit: 10) { error in
let loadedReactions = messageController.reactions
}// get the first 10 reactions
$response = $channel->getReactions('message-id',['limit' => 10]);
// get 3 reactions past the first 10
$response = $channel->getReactions('message-id',['limit' => 3, 'offset' => 10]);// get the first 10 reactions
await channel.getReactions("messageID", PaginationParams(limit: 10));
// get 3 reactions past the first 10
await channel.getReactions("messageID", PaginationParams(limit: 3, offset:10));# get the first 10 reactions
channel.get_reactions(message_id)
# get 3 reactions past the first 10
channel.get_reactions(message_id, limit=3, offset=10)options := map[string][]string{
"limit": {"10"},
"idlte": {"10"},
}
_, err := channel.GetReactions(msgID, options)// get the first 10 reactions
Channel->GetReactions(
Message,
{
10, // Limit
});
// get 3 reactions past the first 10
Channel->GetReactions(
Message,
{
3, // Limit
10, // Offset
});# get the first 10 reactions
channel.get_reactions(message_id)
# get 3 reactions past the first 10
channel.get_reactions(message_id, limit: 3, offset: 10)// get the first 10 reactions
await reactionClient.GetReactionsAsync(message.Id);
// get 3 reactions past the first 10
await reactionClient.GetReactionsAsync(message.Id, offset: 10, limit: 3)// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/// Android SDK
// Get the first 10 reactions
int offset = 0;
int limit = 10;
channelClient.getReactions("message-id", offset, limit).enqueue(result -> {
if (result.isSuccess()) {
List<Reaction> reactions = result.getOrNull();
} else {
// Handle result.error()
}
});
// Get the second 10 reactions
offset = 10;
channelClient.getReactions("message-id", offset, limit)
.enqueue(result -> { /* ... */ });
// Backend SDK
// get 3 reactions past the first 10
Reaction.list(messageId).limit(3).offset(10).request();Querying Reactions
If you need more control on how to fetch the reactions, you can use the query reactions endpoint. This allows you to filter the reactions by their type or the author id, so that you can provide an experience similar to Slack, for example, show all users who reacted with “like”.
// Filter by type
await client.queryReactions(message.id, { type: "like" });
// Filter by user id
const id = uuidv4();
await client.queryReactions(message.id, { user_id: id });
// Paginate the results
const data = await client.queryReactions(message.id, {});
const dataPage2 = await client.queryReactions(
message.id,
{},
{},
{ limit: 5, next: data.next },
);// Filter by type
let reactionListController = client.reactionListController(
query: .init(
messageId: message.id,
filter: .equal(.reactionType, to: "like")
)
)
// Filter by user id
let reactionListController = client.reactionListController(
query: .init(
messageId: message.id,
filter: .equal(.authorId, to: "user123")
)
)
// Synchronize the controller and observe the changes
reactionListController.synchronize()
reactionListController.delegate = self
// Paginate the results
reactionListController.loadMoreReactions()
// Paginate the results with custom limit
reactionListController.loadMoreReactions(limit: 10)