# Reactions

Stream Chat supports message reactions such as likes, hearts, and custom reaction types. Users can react to messages, and reactions can include custom data and scores for cumulative reactions.

## Sending a Reaction

Add a reaction to a message using the `sendReaction` method. Each user can have one reaction of each type per message.

<codetabs>

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

```js
// Add a reaction
const reaction = await channel.sendReaction(messageID, {
  type: "love",
});

// Add a reaction with custom data
const reaction = await channel.sendReaction(messageID, {
  type: "love",
  customField: "value",
});

// Replace all existing reactions from this user with the new one
const reaction = await channel.sendReaction(
  messageID,
  { type: "love" },
  { enforce_unique: true },
);
```

</codetabs-item>

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

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

// Add a reaction with custom data
val reaction = Reaction(
  messageId = "message-id",
  type = "like",
  score = 1,
  extraData = mutableMapOf("customField" to "value"),
)
channelClient.sendReaction(reaction).enqueue { result ->
  if (result is Result.Success) {
    val sentReaction: Reaction = result.value
  } else {
    // Handle Result.Failure
  }
}

// Replace all existing reactions from this user with the new one
channelClient.sendReaction(reaction, enforceUnique = true).enqueue { result ->
  // Handle result
}
```

</codetabs-item>

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

```swift
let channelId = ChannelId(type: .messaging, id: "general")
let messageId = "message-id"
let messageController = chatClient.messageController(cid: channelId, messageId: messageId)

// Add a reaction
messageController.addReaction("like") { error in
  // Handle error
}
```

</codetabs-item>

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

```dart
// Add a reaction
await channel.sendReaction(messageId, "like");

// Add a reaction with custom data
await channel.sendReaction(messageId, "like", extraData: {"customField": "value"});
```

</codetabs-item>

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

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

Reaction reaction = new Reaction();
reaction.setMessageId("message-id");
reaction.setType("like");
reaction.setScore(1);
reaction.getExtraData().put("customField", "value");

channelClient.sendReaction(reaction, false).enqueue(result -> {
  if (result.isSuccess()) {
    Reaction sentReaction = result.data();
  } else {
    // Handle result.error()
  }
});
```

</codetabs-item>

<codetabs-item value="nodejs" label="Node.js">

```js
// Server-side: specify user_id
const reaction = await channel.sendReaction(messageID, {
  type: "love",
  user_id: "user-id",
});
```

</codetabs-item>

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

```python
channel.send_reaction(message_id, {"type": "love", "custom_field": 123}, user_id)
```

</codetabs-item>

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

```php
$response = $channel->sendReaction("message-id", ["type" => "love", "customField" => 123], $userId);
```

</codetabs-item>

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

```ruby
channel.send_reaction(message_id, { type: "love", custom_field: 123 }, user_id)
```

</codetabs-item>

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

```go
reaction := &stream_chat.Reaction{
  Type:      "love",
  ExtraData: map[string]interface{}{"custom_field": 123},
}
msg, err := channel.SendReaction(reaction, msgID, userID)
```

</codetabs-item>

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

```csharp
await reactionClient.SendReactionAsync(message.Id, "love", user.Id);
```

</codetabs-item>

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

```csharp
// Send a reaction with default score of 1
await message.SendReactionAsync("like");

// Send a reaction with custom score
await message.SendReactionAsync("clap", 10);

// Replace all previous reactions from this user
await message.SendReactionAsync("love", enforceUnique: true);
```

</codetabs-item>

</codetabs>

### Reaction Parameters

| Name           | Type    | Description                                                              | Default | Optional |
| -------------- | ------- | ------------------------------------------------------------------------ | ------- | -------- |
| message_id     | string  | ID of the message to react to                                            |         |          |
| type           | string  | Reaction type. Each user can have one reaction of each type per message. |         |          |
| score          | integer | Score for cumulative reactions                                           | 1       | ✓        |
| user_id        | string  | User ID (required for server-side calls)                                 |         | ✓        |
| enforce_unique | boolean | If true, replaces all existing reactions from this user with the new one | false   | ✓        |
| skip_push      | boolean | If true, do not send a push notification                                 | false   | ✓        |
| emoji_code     | string  | Unicode emoji for push notification display                              |         | ✓        |
| custom data    | object  | Custom fields for the reaction                                           |         | ✓        |

<admonition type="warning">

Custom data for reactions is limited to 1KB.

</admonition>

## Removing a Reaction

Remove a reaction by specifying the message ID and reaction type.

<codetabs>

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

```js
await channel.deleteReaction(messageID, "love");
```

</codetabs-item>

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

```kotlin
channelClient.deleteReaction(
  messageId = "message-id",
  reactionType = "like",
).enqueue { result ->
  if (result is Result.Success) {
    val message: Message = result.value
  } else {
    // Handle Result.Failure
  }
}
```

</codetabs-item>

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

```swift
messageController.deleteReaction("like") { error in
  // Handle error
}
```

</codetabs-item>

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

```dart
await channel.deleteReaction(messageId, "like");
```

</codetabs-item>

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

```java
// Android SDK
channelClient.deleteReaction("message-id", "like").enqueue(result -> {
  if (result.isSuccess()) {
    Message message = result.data();
  } else {
    // Handle result.error()
  }
});

// Backend SDK
Reaction.delete(messageId, "like")
  .userId(userId)
  .request();
```

</codetabs-item>

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

```python
channel.delete_reaction(message_id, "love", user_id)
```

</codetabs-item>

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

```php
$response = $channel->deleteReaction("message-id", "love", $userId);
```

</codetabs-item>

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

```ruby
channel.delete_reaction(message_id, "love", user_id)
```

</codetabs-item>

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

```go
_, err := channel.DeleteReaction(msgID, "love", userID)
```

</codetabs-item>

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

```csharp
await reactionClient.DeleteReactionAsync(message.Id, "love", user.Id);
```

</codetabs-item>

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

```csharp
await message.DeleteReactionAsync("like");
```

</codetabs-item>

</codetabs>

## Retrieving Reactions

Reactions are included in the message object. Messages returned by the API include the 10 most recent reactions.

### Reaction Fields in Messages

| Field            | Type   | Description                                                                                     |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------- |
| reaction_counts  | object | Count of reactions per type. Example: `{"love": 3, "fire": 2}`                                  |
| reaction_scores  | object | Sum of scores per type. Equals counts for standard reactions; differs for cumulative reactions. |
| reaction_groups  | object | Detailed statistics per type including count, sum_scores, first_reaction_at, last_reaction_at   |
| latest_reactions | array  | The 10 most recent reactions with type, user_id, and created_at                                 |
| own_reactions    | array  | The current user's reactions on this message                                                    |

<disclosure label="Example Reaction Data">

```json
{
  "reaction_counts": {
    "love": 3,
    "fire": 2,
    "thumbsup": 1
  },
  "reaction_scores": {
    "love": 3,
    "fire": 2,
    "thumbsup": 1
  },
  "reaction_groups": {
    "love": {
      "count": 3,
      "sum_scores": 3,
      "first_reaction_at": "2024-12-11T14:32:00.000Z",
      "last_reaction_at": "2024-12-11T15:18:00.000Z"
    },
    "fire": {
      "count": 2,
      "sum_scores": 2,
      "first_reaction_at": "2024-12-11T14:35:00.000Z",
      "last_reaction_at": "2024-12-11T14:52:00.000Z"
    },
    "thumbsup": {
      "count": 1,
      "sum_scores": 1,
      "first_reaction_at": "2024-12-11T16:05:00.000Z",
      "last_reaction_at": "2024-12-11T16:05:00.000Z"
    }
  },
  "latest_reactions": [
    {
      "type": "thumbsup",
      "user_id": "sarah-miller",
      "created_at": "2024-12-11T16:05:00.000Z"
    },
    {
      "type": "love",
      "user_id": "mike-johnson",
      "created_at": "2024-12-11T15:18:00.000Z"
    },
    {
      "type": "fire",
      "user_id": "emma-wilson",
      "created_at": "2024-12-11T14:52:00.000Z"
    }
  ],
  "own_reactions": []
}
```

</disclosure>

<admonition type="info">

Use `reaction_groups` instead of `reaction_counts` for if you're building a custom implementation. The `reaction_groups` field provides additional metadata including timestamps and is the recommended approach.

</admonition>

To retrieve more than 10 reactions, use pagination.

### Paginating Reactions

Retrieve reactions with pagination using `limit` and `offset` parameters.

| Parameter | Maximum Value |
| --------- | ------------- |
| limit     | 300           |
| offset    | 1000          |

<codetabs>

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

```js
// Get the first 10 reactions
const response = await channel.getReactions(messageID, { limit: 10 });

// Get reactions 11-13
const response = await channel.getReactions(messageID, {
  limit: 3,
  offset: 10,
});
```

</codetabs-item>

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

```kotlin
// 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 reactions 11-20
channelClient.getReactions(
  messageId = "message-id",
  offset = 10,
  limit = 10,
).enqueue { /* ... */ }

// Get reactions after a specific reaction ID
channelClient.getReactions(
  messageId = "message-id",
  firstReactionId = "reaction-id",
  limit = 10,
).enqueue { /* ... */ }
```

</codetabs-item>

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

```swift
// Load first 10 reactions
messageController.loadReactions(limit: 10, offset: 0) { result in
  let loadedReactions = messageController.reactions
}

// Load next 10 reactions
messageController.loadNextReactions(limit: 10) { error in
  let loadedReactions = messageController.reactions
}
```

</codetabs-item>

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

```dart
// Get the first 10 reactions
await channel.getReactions(messageId, PaginationParams(limit: 10));

// Get reactions 11-13
await channel.getReactions(messageId, PaginationParams(limit: 3, offset: 10));
```

</codetabs-item>

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

```java
// Android SDK
int offset = 0;
int limit = 10;

// Get the first 10 reactions
channelClient.getReactions("message-id", offset, limit).enqueue(result -> {
  if (result.isSuccess()) {
    List<Reaction> reactions = result.data();
  } else {
    // Handle result.error()
  }
});

// Get reactions 11-20
channelClient.getReactions("message-id", 10, limit).enqueue(result -> { /* ... */ });

// Backend SDK
Reaction.list(messageId).limit(10).offset(0).request();
```

</codetabs-item>

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

```python
# Get the first 10 reactions
channel.get_reactions(message_id, limit=10)

# Get reactions 11-13
channel.get_reactions(message_id, limit=3, offset=10)
```

</codetabs-item>

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

```php
// Get the first 10 reactions
$response = $channel->getReactions("message-id", ["limit" => 10]);

// Get reactions 11-13
$response = $channel->getReactions("message-id", ["limit" => 3, "offset" => 10]);
```

</codetabs-item>

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

```ruby
# Get the first 10 reactions
channel.get_reactions(message_id, limit: 10)

# Get reactions 11-13
channel.get_reactions(message_id, limit: 3, offset: 10)
```

</codetabs-item>

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

```go
options := map[string][]string{
  "limit": {"10"},
}
_, err := channel.GetReactions(msgID, options)
```

</codetabs-item>

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

```csharp
// Get the first 10 reactions
await reactionClient.GetReactionsAsync(message.Id, limit: 10);

// Get reactions 11-13
await reactionClient.GetReactionsAsync(message.Id, offset: 10, limit: 3);
```

</codetabs-item>

</codetabs>

## Querying Reactions

Filter reactions by type or user on a specific message. This endpoint requires the user to have read permission on the channel when called client-side.

<codetabs>

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

```js
// Query reactions by type
await client.queryReactions(message.id, { type: "like" });

// Query reactions by user
await client.queryReactions(message.id, { user_id: userId });

// Paginate results
const firstPage = await client.queryReactions(message.id, {});
const secondPage = await client.queryReactions(
  message.id,
  {},
  {},
  { limit: 5, next: firstPage.next },
);
```

</codetabs-item>

</codetabs>

## Cumulative Reactions

Cumulative reactions allow users to react multiple times to the same message, with the total score tracked. This is useful for features like Medium's "clap" functionality.

Set a `score` value when sending the reaction. The API returns:

- `sum_scores`: Total score across all users
- Individual user scores

<codetabs>

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

```js
// User claps 5 times
await channel.sendReaction(messageID, {
  type: "clap",
  score: 5,
});

// Same user claps 20 more times (total becomes 25)
await channel.sendReaction(messageID, {
  type: "clap",
  score: 25,
});
```

</codetabs-item>

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

```kotlin
val reaction = Reaction(messageId = "message-id", type = "clap", score = 5)
channelClient.sendReaction(reaction).enqueue { /* ... */ }
```

</codetabs-item>

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

```swift
messageController.addReaction("clap", score: 5) { error in
  // Handle error
}
```

</codetabs-item>

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

```dart
// User claps 5 times
await channel.sendReaction(messageId, "clap", score: 5);

// Same user claps 20 more times
await channel.sendReaction(messageId, "clap", score: 25);
```

</codetabs-item>

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

```java
// Android SDK
Reaction reaction = new Reaction();
reaction.setMessageId("message-id");
reaction.setType("clap");
reaction.setScore(5);

channelClient.sendReaction(reaction, false).enqueue(result -> { /* ... */ });

// Backend SDK
Reaction.send(messageId)
  .reaction(ReactionRequestObject.builder().type("clap").score(5).userId(userId).build())
  .request();
```

</codetabs-item>

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

```python
# User claps 5 times
channel.send_reaction(message_id, {"type": "clap", "score": 5}, user_id)

# Same user claps 20 more times
channel.send_reaction(message_id, {"type": "clap", "score": 25}, user_id)
```

</codetabs-item>

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

```php
// User claps 5 times
$channel->sendReaction("message-id", ["type" => "clap", "score" => 5], $userId);

// Same user claps 20 more times
$channel->sendReaction("message-id", ["type" => "clap", "score" => 25], $userId);
```

</codetabs-item>

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

```ruby
# User claps 5 times
channel.send_reaction(message_id, { type: "clap", score: 5 }, user_id)

# Same user claps 20 more times
channel.send_reaction(message_id, { type: "clap", score: 25 }, user_id)
```

</codetabs-item>

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

```go
_, err = channel.SendReaction(&stream_chat.Reaction{
  Type:      "clap",
  ExtraData: map[string]interface{}{"score": 25},
}, msgID, userID)
```

</codetabs-item>

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

```csharp
var reaction = new ReactionRequest { Type = "clap", UserId = user.Id, Score = 5 };
await reactionClient.SendReactionAsync(message.Id, reaction);
```

</codetabs-item>

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

```csharp
await message.SendReactionAsync("clap", score: 5);
```

</codetabs-item>

</codetabs>


---

This page was last updated at 2026-03-04T14:23:50.472Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/go-golang/send_reaction/](https://getstream.io/chat/docs/go-golang/send_reaction/).