# Comments

Comments support voting, ranking, threading, images, URL previews, mentions and notifications.

## Adding Comments

```dart label="Dart"
// Adding a comment to an activity
final comment = await feed.addComment(
  request: const ActivityAddCommentRequest(
    id: 'comment_123', // id is optional, but must be unique. will be auto-generated if not provided
    comment: 'So great!',
    custom: {'sentiment': 'positive'},
    activityId: 'activity_123',
    activityType: 'activity',
  ),
);

// Adding a reply to a comment
final reply = await feed.addComment(
  request: const ActivityAddCommentRequest(
    comment: 'I agree!',
    parentId: 'comment_456',
  ),
);

// Adding a comment with attachments
final commentWithAttachment = await feed.addComment(
  request: const ActivityAddCommentRequest(
    comment: 'Check out this image!',
    activityId: 'activity_123',
    activityType: 'activity',
    attachments: [
      Attachment(
        imageUrl: 'https://example.com/image.jpg',
        type: 'image',
        custom: {'width': 600, 'height': 400},
      ),
    ],
  ),
);
```

<Admonition type="info">

You can use [Stream's CDN](https://getstream.io/activity-feeds/docs/flutter/file-uploads/) for storing and quickly accessing files attached to comments.

</Admonition>

### Comment request options

<h4 id="AddCommentRequest"><a href="#AddCommentRequest">AddCommentRequest</a></h4><table><thead><tr><th>Name</th><th>Type</th><th>Description</th><th>Constraints</th></tr></thead><tbody><tr><td><code>attachments</code></td><td><code>Attachment[]</code></td><td>Media attachments for the reply</td><td>-</td></tr><tr><td><code>comment</code></td><td><code>string</code></td><td>Text content of the comment</td><td>-</td></tr><tr><td><code>copy_custom_to_notification</code></td><td><code>boolean</code></td><td>Whether to copy custom data to the notification activity (only applies when create_notification_activity is true)</td><td>-</td></tr><tr><td><code>create_notification_activity</code></td><td><code>boolean</code></td><td>Whether to create a notification activity for this comment</td><td>-</td></tr><tr><td><code>custom</code></td><td><code>object</code></td><td>Custom data for the comment</td><td>-</td></tr><tr><td><code>id</code></td><td><code>string</code></td><td>Optional custom ID for the comment (max 255 characters). If not provided, a UUID will be generated.</td><td>-</td></tr><tr><td><code>mentioned_user_ids</code></td><td><code>string[]</code></td><td>List of users mentioned in the reply</td><td>-</td></tr><tr><td><code>object_id</code></td><td><code>string</code></td><td>ID of the object to comment on. Required for root comments</td><td>-</td></tr><tr><td><code>object_type</code></td><td><code>string</code></td><td>Type of the object to comment on. Required for root comments</td><td>-</td></tr><tr><td><code>parent_id</code></td><td><code>string</code></td><td>ID of parent comment for replies. When provided, object_id and object_type are automatically inherited from the parent comment.</td><td>-</td></tr><tr><td><code>skip_enrich_url</code></td><td><code>boolean</code></td><td>Whether to skip URL enrichment for this comment</td><td>-</td></tr><tr><td><code>skip_push</code></td><td><code>boolean</code></td><td>-</td><td>-</td></tr><tr><td><code>user</code></td><td><code>UserRequest</code></td><td>-</td><td>-</td></tr><tr><td><code>user_id</code></td><td><code>string</code></td><td>-</td><td>-</td></tr></tbody></table>

## Updating Comments

`updateComment` endpoint performs a partial update: only the fields you include in the request are changed, and each of those fields is completely overwritten.

```dart label="Dart"
// Updating a comment
final response = await feed.updateComment(
  commentId: 'comment_123',
  request: const UpdateCommentRequest(comment: 'Not so great'),
);
print('Comment edited at: ${response.comment.editedAt}');
```

## Removing Comments

```dart label="Dart"
await feed.deleteComment(commentId: 'comment_123');
```

## Reading Comments

You'll also want to show/return these comments. The most important is when reading the feed.

```dart label="Dart"
await feed.getOrCreate();
print(feed.state.activities[0].comments);
// or
final activity = client.activity(
  fid: const FeedId(group: 'user', id: 'john'),
  activityId: 'activity_123',
);
await activity.get();
print(activity.state.comments);

// Reading a single comment
final comment = await client.getComment(id: '123');
```

### Sort options

The following sort options are supported when reading comments:

- `last`: newest comment returned first
- `first`: oldest comment returned first
- `top`: highest score returned first - computed from `upvote` - `downvote` reaction types
- `controversial`: controversial comment returned first - mixed reactions (`upvote` and `downvote`) and lots of comments
- `best`: highest Wilson score returned first - Wilson score balances reaction score (`upvote` - `downvote`) with number of reactions (a comment with lower reaction score but more sum reactions is returned before a comment with higher score, but few sum reactions)

## Search for Comments

You can also query the comments, the following examples show

- how to search across all comments by text
- query all comments of a given user

```dart label="Dart"
// Search in comment texts
final list1 = client.commentList(
  const CommentsQuery(
    filter: Filter.query(CommentsFilterField.commentText, 'oat'),
  ),
);
final comments1 = await list1.get();

// Comments from an user
final list2 = client.commentList(
  const CommentsQuery(
    filter: Filter.equal(CommentsFilterField.userId, 'jane'),
  ),
);
final comments2 = await list2.get();
```

### Comment Queryable Built-In Fields

| name                | type                                              | description                                                   | supported operations                                               | example                                               |
| ------------------- | ------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------- |
| `id`                | string or list of strings                         | The ID of the comment                                         | `$in`, `$eq`                                                       | `{ id: { $in: [ 'comment_123', 'comment_456' ] } }`   |
| `user_id`           | string or list of strings                         | The ID of the user who created the comment                    | `$in`, `$eq`                                                       | `{ user_id: { $eq: 'user_123' } }`                    |
| `object_type`       | string or list of strings                         | The type of object being commented on                         | `$eq`, `$ne`, `$in`, `$nin`                                        | `{ object_type: { $in: [ 'activity', 'post' ] } }`    |
| `object_id`         | string or list of strings                         | The ID of the object being commented on                       | `$in`, `$eq`                                                       | `{ object_id: { $eq: 'activity_123' } }`              |
| `parent_id`         | string or list of strings                         | The parent comment ID for replies                             | `$in`, `$eq`                                                       | `{ parent_id: { $eq: 'comment_parent_123' } }`        |
| `comment_text`      | string                                            | The text content of the comment                               | `$q`                                                               | `{ comment_text: { $q: 'search terms' } }`            |
| `reply_count`       | number                                            | The number of replies to this comment                         | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ reply_count: { $gte: 5 } }`                        |
| `upvote_count`      | number                                            | The number of upvotes on the comment                          | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ upvote_count: { $gte: 10 } }`                      |
| `downvote_count`    | number                                            | The number of downvotes on the comment                        | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ downvote_count: { $lt: 5 } }`                      |
| `score`             | number                                            | The overall score of the comment                              | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ score: { $gte: 0 } }`                              |
| `confidence_score`  | number                                            | The confidence score of the comment                           | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ confidence_score: { $gte: 0.5 } }`                 |
| `controversy_score` | number                                            | The controversy score of the comment                          | `$gt`, `$gte`, `$lt`, `$lte`                                       | `{ controversy_score: { $lt: 0.8 } }`                 |
| `created_at`        | string, must be formatted as an RFC3339 timestamp | The time the comment was created                              | `$eq`, `$gt`, `$gte`, `$lt`, `$lte`                                | `{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }` |
| `custom.<key>`      | string, number, boolean, or JSON (as stored)      | Values from the comment `custom` object. **Enterprise only.** | `$eq`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$exists`, `$contains` | `{ 'custom.priority': { $gte: 10 } }`                 |

### Comment sort options

All fields support `1` and `-1` directions.

- `created_at`
- `score`: same as [`top` sort option](#sort-options)
- `confidence_score` - same as [`best` sort option](#sort-options)
- `controversy_score` - same as [`controversial` sort option](#sort-options)
- `upvote_count`
- `downvote_count`

## Comment Reactions

When adding reactions and the `enforce_unique` flag is set to `true`, the existing reaction of a user will be overridden with the new reaction. Use this flag if you want to ensure users have a single reaction per each comment/activity. The default value is `false`, in which case users can have multiple reactions.

```dart label="Dart"
// Add a reaction to a comment
await feed.addCommentReaction(
  commentId: 'comment_123',
  request: const AddCommentReactionRequest(
    type: 'like',
    // Optionally override existing reaction
    enforceUnique: true,
  ),
);
// Remove a reaction from a comment
await feed.deleteCommentReaction(commentId: 'comment_123', type: 'like');
```

### Overview of the reaction model

<h5 id="FeedsReactionResponse"><a href="#FeedsReactionResponse">FeedsReactionResponse</a></h5><table><thead><tr><th>Name</th><th>Type</th><th>Description</th><th>Constraints</th></tr></thead><tbody><tr><td><code>activity_id</code></td><td><code>string</code></td><td>ID of the activity that was reacted to</td><td>Required</td></tr><tr><td><code>comment_id</code></td><td><code>string</code></td><td>ID of the comment that was reacted to</td><td>-</td></tr><tr><td><code>created_at</code></td><td><code>number</code></td><td>When the reaction was created</td><td>Required</td></tr><tr><td><code>custom</code></td><td><code>object</code></td><td>Custom data for the reaction</td><td>-</td></tr><tr><td><code>type</code></td><td><code>string</code></td><td>Type of reaction</td><td>Required</td></tr><tr><td><code>updated_at</code></td><td><code>number</code></td><td>When the reaction was last updated</td><td>Required</td></tr><tr><td><code>user</code></td><td><code>UserResponse</code></td><td>User who created the reaction</td><td>Required</td></tr></tbody></table>

## Comment Threading

```dart label="Dart"
final commentList = client.activityCommentList(
  const ActivityCommentsQuery(
    objectId: 'activity_123',
    objectType: 'activity',
    depth: 3,
    limit: 20,
  ),
);
final comments = await commentList.get();

// Get replies of a specific parent comment
final replyList = client.commentReplyList(
  const CommentRepliesQuery(commentId: 'parent_123'),
);
final replies = await replyList.get();
```

Reading comment replies supports the [same sort parameters](#sort-options) as reading comments does.

## Restricting comment replies

### Set who can add comments

When creating an activity it's possible to set who can add comments. Possible options:

- Everyone (this is the default setting)
- Only people I follow
- Nobody

<Admonition type="info">

The activity author is always allowed to add comments regardless of the reply settings.

</Admonition>

```js label="JavaScript"
const response = await feed.addActivity({
  type: "post",
  text: "apple stock will go up",
  restrict_replies: "people_i_follow", // Options: "everyone", "people_i_follow", "nobody"
});
```

### Show/hide comment input

If a user isn't allowed to add comments, it's a good idea to hide the comment input.

When everyone/nobody can comment this is straightforward. However if only people the activity author follows can comment, we have to check if there are any feeds owned by the current user that is followed by the activity author, the code snippet below shows how to check this:

```js label="JavaScript"
const activity: ActivityResponse = /* fetch a single activity or read a feed */;

// Lists follow relationships where
// - target feed is owned by current user
// - source feed is owned by activity author
const feed = client.feed(
  activity.current_feed.group_id,
  activity.current_feed.id,
);
console.log(feed.currentState.own_followings);
```

<Admonition type="info">

`own_followings` is only set when reading a feed/activity from client-side, for server-side requests it will be empty.

</Admonition>

- When fetching a single activity, `own_followings` is set by default
- When reading a feed, you have to explicitly enable fetching `own_followings`:

```js label="JavaScript"
feed.getOrCreate({ enrichment_options: { enrich_own_followings: true } });
```

## Overview of the comment model

Comment text can be translated on demand and projected when reading comments. See [Translation](https://getstream.io/activity-feeds/docs/flutter/translation/) for translate endpoints, read-time `language` projection, and the `i18n` object format.

<h4 id="CommentResponse"><a href="#CommentResponse">CommentResponse</a></h4><table><thead><tr><th>Name</th><th>Type</th><th>Description</th><th>Constraints</th></tr></thead><tbody><tr><td><code>attachments</code></td><td><code>Attachment[]</code></td><td>Attachments associated with the comment</td><td>-</td></tr><tr><td><code>confidence_score</code></td><td><code>number</code></td><td>Confidence score of the comment</td><td>Required</td></tr><tr><td><code>controversy_score</code></td><td><code>number</code></td><td>Controversy score of the comment</td><td>-</td></tr><tr><td><code>created_at</code></td><td><code>number</code></td><td>When the comment was created</td><td>Required</td></tr><tr><td><code>custom</code></td><td><code>object</code></td><td>Custom data for the comment</td><td>-</td></tr><tr><td><code>deleted_at</code></td><td><code>number</code></td><td>When the comment was deleted</td><td>-</td></tr><tr><td><code>downvote_count</code></td><td><code>integer</code></td><td>Number of downvotes for this comment</td><td>Required</td></tr><tr><td><code>edited_at</code></td><td><code>number</code></td><td>When the comment was last edited</td><td>-</td></tr><tr><td><code>id</code></td><td><code>string</code></td><td>Unique identifier for the comment</td><td>Required</td></tr><tr><td><code>latest_reactions</code></td><td><code>FeedsReactionResponse[]</code></td><td>Recent reactions to the comment</td><td>-</td></tr><tr><td><code>mentioned_users</code></td><td><code>UserResponse[]</code></td><td>Users mentioned in the comment</td><td>Required</td></tr><tr><td><code>moderation</code></td><td><code>ModerationV2Response</code></td><td>Moderation details for the comment</td><td>-</td></tr><tr><td><code>object_id</code></td><td><code>string</code></td><td>ID of the object this comment is associated with</td><td>Required</td></tr><tr><td><code>object_type</code></td><td><code>string</code></td><td>Type of the object this comment is associated with</td><td>Required</td></tr><tr><td><code>own_reactions</code></td><td><code>FeedsReactionResponse[]</code></td><td>Current user&#39;s reactions to this activity</td><td>Required</td></tr><tr><td><code>parent_id</code></td><td><code>string</code></td><td>ID of parent comment for nested replies</td><td>-</td></tr><tr><td><code>reaction_count</code></td><td><code>integer</code></td><td>Number of reactions to this comment</td><td>Required</td></tr><tr><td><code>reaction_groups</code></td><td><code>object</code></td><td>Grouped reactions by type</td><td>-</td></tr><tr><td><code>reply_count</code></td><td><code>integer</code></td><td>Number of replies to this comment</td><td>Required</td></tr><tr><td><code>score</code></td><td><code>integer</code></td><td>Score of the comment based on reactions</td><td>Required</td></tr><tr><td><code>status</code></td><td><code>string (active, deleted, removed, hidden, shadow_blocked)</code></td><td>Status of the comment. One of: active, deleted, removed, hidden</td><td>Required</td></tr><tr><td><code>text</code></td><td><code>string</code></td><td>Text content of the comment</td><td>-</td></tr><tr><td><code>updated_at</code></td><td><code>number</code></td><td>When the comment was last updated</td><td>Required</td></tr><tr><td><code>upvote_count</code></td><td><code>integer</code></td><td>Number of upvotes for this comment</td><td>Required</td></tr><tr><td><code>user</code></td><td><code>UserResponse</code></td><td>User who created the comment</td><td>Required</td></tr></tbody></table>

## Add comments in batch

```dart label="Dart"
final response = await feed.addCommentsBatch(
  request: AddCommentsBatchRequest(
    comments: [
      const ActivityAddCommentRequest(
        id: 'comment_123', // id is optional, but must be unique. will be auto-generated if not provided
        comment: 'So great!',
        custom: {'sentiment': 'positive'},
        activityId: 'activity_123',
        activityType: 'activity',
      ),
    ],
  ),
);
```


---

This page was last updated at 2026-08-07T20:37:30.018Z.

For the most recent version of this documentation, visit [https://getstream.io/activity-feeds/docs/flutter/comments/](https://getstream.io/activity-feeds/docs/flutter/comments/).