// Adding a comment to an activity let comment = try await feed.addComment( request: .init( comment: "So great!", custom: ["sentiment": "positive"], objectId: "activity_123", objectType: "activity", ) ) // Adding a reply to a comment let reply = try await feed.addComment( request: .init( comment: "I agree!", objectId: "activity_123", objectType: "activity", parentId: "comment_456" ) )Activity Feeds v3 is in beta — try it out!
Comments
Overview
Comments support voting, ranking, threading, images, URL previews, mentions and notifications.
Adding Comments
// Adding a comment to an activity val comment: Result<CommentData> = feed.addComment( request = ActivityAddCommentRequest( comment = "So great!", custom = mapOf("sentiment" to "positive"), activityId = "activity_123" ) ) // Adding a reply to a comment val reply: Result<CommentData> = feed.addComment( request = ActivityAddCommentRequest( comment = "I agree!", activityId = "activity_123", parentId = "comment_456" ) )// Adding a comment to an activity await client.addComment({ comment: "So great!", object_id: "activity_123", object_type: "activity", custom: { sentiment: "positive", }, }); // Adding a reply to a comment await client.addComment({ comment: "I agree!", object_id: "activity_123", object_type: "activity", parent_id: "comment_456", }); // Adding a comment without triggering push notifications await client.addComment({ comment: "Silent comment", object_id: "activity_123", object_type: "activity", skip_push: true, });// Adding a comment to an activity final comment = await feed.addComment( request: const ActivityAddCommentRequest( 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!', activityId: 'activity_123', activityType: 'activity', parentId: 'comment_456', ), );// Adding a comment to an activity await serverClient.feeds.addComment({ comment: "So great!", object_id: "activity_123", object_type: "activity", user_id: "<user_id>", custom: { sentiment: "positive", }, }); // Adding a reply to a comment await serverClient.feeds.addComment({ comment: "I agree!", object_id: "activity_123", object_type: "activity", parent_id: "comment_456", user_id: "<user_id>", }); // Adding a comment without triggering push notifications await serverClient.feeds.addComment({ comment: "Silent comment", object_id: "activity_123", object_type: "activity", user_id: "<user_id>", skip_push: true, });// Get feed instance feed := client.Feeds().Feed("user", "john") feedResponse, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("john"), }) activity := feedResponse.Data.Activities[0] activityID := activity.ID commentID := "6b6dd9df-13b0-4b47-8d73-a45a00d04fa7" // folderID := "11e7d97a-e461-47f0-8d24-cd8a86168a60" // Adding a comment to an activity _, err = client.Feeds().AddComment(context.Background(), &getstream.AddCommentRequest{ Comment: "So great!", ObjectID: activityID, ObjectType: "activity", UserID: getstream.PtrTo("john"), Custom: map[string]any{ "sentiment": "positive", }, }) if err != nil { log.Fatal("Error adding comment:", err) } // Adding a reply to a comment _, err = client.Feeds().AddComment(context.Background(), &getstream.AddCommentRequest{ Comment: "I agree!", ObjectID: activityID, ObjectType: "activity", ParentID: getstream.PtrTo(commentID), UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error adding reply:", err) } // Adding a comment without triggering push notifications _, err = client.Feeds().AddComment(context.Background(), &getstream.AddCommentRequest{ Comment: "Silent comment", ObjectID: activityID, ObjectType: "activity", UserID: getstream.PtrTo("john"), SkipPush: getstream.PtrTo(true), }) if err != nil { log.Fatal("Error adding silent comment:", err) }AddCommentRequest commentRequest = AddCommentRequest.builder() .comment("This is a test comment from Java SDK") .objectID(activityId) .objectType("activity") .userID(testUserId) .build(); AddCommentResponse response = feeds.addComment(commentRequest).execute().getData();// Adding a comment to an activity $response = $feedsClient->addComment( new GeneratedModels\AddCommentRequest( comment: 'So great!', objectID: 'activity_123', objectType: 'activity', userID: 'user123', custom: (object)[ 'sentiment' => 'positive' ] ) ); // Adding a reply to a comment $response = $feedsClient->addComment( new GeneratedModels\AddCommentRequest( comment: 'I agree!', objectID: 'activity_123', objectType: 'activity', parentID: 'comment_456', userID: 'user123' ) ); // Adding a comment without triggering push notifications $response = $feedsClient->addComment( new GeneratedModels\AddCommentRequest( comment: 'Silent comment', objectID: 'activity_123', objectType: 'activity', userID: 'user123', skipPush: true ) );var response = await _feedsV3Client.AddCommentAsync( new AddCommentRequest { Comment = "This is a test comment from .NET SDK", ObjectID = activityId, ObjectType = "activity", UserID = _testUserId } );response = self.client.feeds.add_comment( comment="This is a test comment from Python SDK", object_id=activity_id, object_type="activity", user_id=self.test_user_id, )# Adding a comment to an activity comment_request = GetStream::Generated::Models::AddCommentRequest.new( comment: 'So great!', object_id: 'activity_123', object_type: 'activity', user_id: 'user123', custom: { sentiment: 'positive' } ) response = client.feeds.add_comment(comment_request) # Adding a reply to a comment reply_request = GetStream::Generated::Models::AddCommentRequest.new( comment: 'I agree!', object_id: 'activity_123', object_type: 'activity', parent_id: 'comment_456', user_id: 'user123' ) response = client.feeds.add_comment(reply_request) # Adding a comment without triggering push notifications silent_comment_request = GetStream::Generated::Models::AddCommentRequest.new( comment: 'Silent comment', object_id: 'activity_123', object_type: 'activity', user_id: 'user123', skip_push: true ) response = client.feeds.add_comment(silent_comment_request)Updating Comments
try await feed.updateComment( commentId: "comment_123", request: .init( comment: "Not so great", custom: ["edited": true] ) )feed.updateComment( commentId = "comment_123", request = UpdateCommentRequest( comment = "Not so great", custom = mapOf("edited" to true) ) )// Update a comment await client.updateComment({ id: "comment_123", comment: "Updated comment", custom: { edited: true, }, });// Updating a comment final updatedComment = await feed.updateComment( commentId: 'comment_123', request: const UpdateCommentRequest( comment: 'Not so great', custom: {'edited': true}, ), );// Update a comment await client.feeds.updateComment({ id: "comment_123", comment: "Updated comment", custom: { edited: true, }, });_, err = client.Feeds().UpdateComment(context.Background(), commentID, &getstream.UpdateCommentRequest{ Comment: getstream.PtrTo("Updated comment"), Custom: map[string]any{ "edited": true, }, }) if err != nil { log.Fatal("Error updating comment:", err) }AddCommentRequest commentRequest = AddCommentRequest.builder() .comment("This is a test comment from Java SDK") .objectID(activityId) .objectType("activity") .userID(testUserId) .build(); AddCommentResponse response = feeds.addComment(commentRequest).execute().getData();// Update a comment $response = $feedsClient->updateComment( 'comment_123', new GeneratedModels\UpdateCommentRequest( comment: 'Updated comment', custom: (object)[ 'edited' => true ] ) );var response = await _feedsV3Client.AddCommentAsync( new AddCommentRequest { Comment = "This is a test comment from .NET SDK", ObjectID = activityId, ObjectType = "activity", UserID = _testUserId } );response = self.client.feeds.add_comment( comment="This is a test comment from Python SDK", object_id=activity_id, object_type="activity", user_id=self.test_user_id, )Removing Comments
try await feed.deleteComment( commentId: "comment_123" )feed.deleteComment(commentId = "comment_123")client.deleteComment({ id: "comment_123", });await feed.deleteComment(commentId: 'comment_123');client.feeds.deleteComment({ id: "comment_123", });_, err = client.Feeds().DeleteComment(context.Background(), commentID, &getstream.DeleteCommentRequest{}) if err != nil { log.Fatal("Error deleting comment:", err) }UpdateCommentRequest updateRequest = UpdateCommentRequest.builder().comment("Updated comment text from Java SDK").build(); UpdateCommentResponse response = feeds.updateComment(commentId, updateRequest).execute().getData();// Delete a comment (soft delete) $response = $feedsClient->deleteComment('comment_123', false);var response = await _feedsV3Client.UpdateCommentAsync( commentId, new UpdateCommentRequest { Comment = "Updated comment text from .NET SDK" } );response = self.client.feeds.update_comment( comment_id, comment="Updated comment text from Python SDK" )# Update a comment update_request = GetStream::Generated::Models::UpdateCommentRequest.new( comment: 'Updated comment text from Ruby SDK', custom: { edited: true } ) response = client.feeds.update_comment(comment_id, update_request)Reading Comments
You’ll also want to show/return these comments. The most important is when reading the feed.
try await feed.getOrCreate() print(feed.state.activities[0].comments) // or let activity = client.activity( for: "activity_123", in: FeedId(group: "user", id: "john") ) try await activity.get() print(activity.state.comments)feed.getOrCreate() feed.state.activities.collect { it.first().comments } // or val activity = client.activity( activityId = "activity_123", fid = FeedId(group = "user", id = "john") ) activity.get() activity.state.commentsawait feed.getOrCreate(); const activity = feed.state.getLatestValue().activities?.[0]!; // Supported values for sort: first, last, top, controversial, best // Loads the activity comments (first or next page) and stores them in feed state await feed.loadNextPageActivityComments(activity, { sort: 'best' }); // To read comments without storing them in feed state const response = client.getComments({ object_type: "activity", object_id: "123", limit: 10, sort: "best", });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);const response = feed.getOrCreate({ user_id: "<user id>", }); console.log(response.activities[0].comments); // Or using the getComments endpoint const comments = await client.feeds.getComments({ object_type: "activity", object_id: "123", limit: 10, sort: "best", });feed := client.Feeds().Feed("user", "john") feedResponse, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal(err) } // Access comments from the first activity activity := feedResponse.Data.Activities[0] comments := activity.Comments // Or using the getComments endpoint commentsResponse, err := client.Feeds().GetComments(context.Background(), &getstream.GetCommentsRequest{ ObjectType: "activity", ObjectID: "123", Limit: getstream.PtrTo(10), Sort: getstream.PtrTo("best"), }) if err != nil { log.Fatal(err) } commentsFromEndpoint := commentsResponse.Data.CommentsDeleteCommentRequest deleteRequest = DeleteCommentRequest.builder().build(); DeleteCommentResponse response = feeds.deleteComment(commentId, deleteRequest).execute().getData();// Get comments for an activity // activity id, object type, depth, sort, replies limit, limit, prev, next $response = $feedsClient->getComments('activity_123', 'activity', 3, 'best', 10, 10, '', ''); echo json_encode($response->getData()); // Access comments from feed response $feedResponse = $feedsClient->feed('user', 'eric')->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest( userID: 'eric' ) ); $comments = $feedResponse->getData()->activities[0]['comments'];var response = await _feedsV3Client.DeleteCommentAsync( commentId, new { user_id = _testUserId } );response = self.client.feeds.delete_comment( comment_id, hard_delete=False ) # soft delete# Delete a comment (soft delete) response = client.feeds.delete_comment(comment_id, hard_delete: false)Querying Comments
You can also query the comments so you can show all comments for a given activity or user:
// Search in comment texts let list1 = client.commentList( for: .init( filter: .query(.commentText, "oat") ) ) let comments1 = try await list1.get() // Comments from an user let list2 = client.commentList( for: .init( filter: .equal(.userId, "jane") ) ) let comments2 = try await list2.get()// Search in comment texts val list1 = client.commentList( query = CommentsQuery( filter = CommentsFilterField.commentText.query("oat") ) ) val comments1: Result<List<CommentData>> = list1.get() // Comments from a user val list2 = client.commentList( query = CommentsQuery( filter = CommentsFilterField.userId.equal("jane") ) ) val comments2: Result<List<CommentData>> = list2.get()// Search in comment texts await client.queryComments({ filter: { comment_text: { $q: "oat" } }, }); // Comments of a user await client.queryComments({ filter: { user_id: jane.id, }, limit: 20, });// 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();// Search in comment texts await client.feeds.queryComments({ filter: { comment_text: { $q: "oat" } }, }); // Comments of a user await client.feeds.queryComments({ filter: { user_id: jane.id, }, limit: 20, });// Search in comment texts _, err = client.Feeds().QueryComments(context.Background(), &getstream.QueryCommentsRequest{ Filter: map[string]any{ "comment_text": map[string]any{ "$q": "oat", }, }, }) if err != nil { log.Printf("Error searching comments: %v", err) } // Comments by user _, err = client.Feeds().QueryComments(context.Background(), &getstream.QueryCommentsRequest{ Filter: map[string]any{ "user_id": "jane", }, Limit: getstream.PtrTo(20), }) if err != nil { log.Printf("Error querying user comments: %v", err) }Map<String, Object> filter = new HashMap<>(); filter.put("object_id", activityId); QueryCommentsRequest queryRequest = QueryCommentsRequest.builder().filter(filter).limit(10).build(); QueryCommentsResponse response = feeds.queryComments(queryRequest).execute().getData();// Search in comment texts $response = $feedsClient->queryComments( new GeneratedModels\QueryCommentsRequest( filter: (object)['comment_text' => ['$q' => 'oat']], limit: 10 ) ); // Comments of a user $response = $feedsClient->queryComments( new GeneratedModels\QueryCommentsRequest( filter: (object)['user_id' => 'jane'], limit: 20 ) ); // Query comments for an activity $response = $feedsClient->queryComments( new GeneratedModels\QueryCommentsRequest( filter: (object)['object_id' => 'activity_123'], limit: 10 ) );var response = await _feedsV3Client.QueryCommentsAsync( new QueryCommentsRequest { Filter = new Dictionary<string, object> { ["object_id"] = activityId }, Limit = 10 } );response = self.client.feeds.query_comments( filter={"object_id": activity_id}, limit=10 )# Query comments for an activity query_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { object_id: activity_id }, limit: 10 ) response = client.feeds.query_comments(query_request) # Search in comment texts search_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { comment_text: { '$q' => 'oat' } } ) response = client.feeds.query_comments(search_request) # Comments from a specific user user_comments_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { user_id: 'user123' }, limit: 20 ) response = client.feeds.query_comments(user_comments_request)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' } } |
status | string or list of strings | The status of the comment | $eq, $ne, $in | { status: { $in: [ 'approved', 'pending' ] } } |
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' } } |
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.
// Add a reaction to a comment try await feed.addCommentReaction( commentId: "comment_123", request: .init(type: "like") ) // Remove a reaction from a comment try await feed.deleteCommentReaction( commentId: "comment_123", type: "like" )// Add a reaction to a comment feed.addCommentReaction( commentId = "comment_123", request = AddCommentReactionRequest( type = "like", // Optionally override existing reaction enforceUnique = true ) ) // Remove a reaction from a comment feed.deleteCommentReaction( commentId = "comment_123", type = "like" )// Add a reaction to a comment const response = await client.addCommentReaction({ id: "comment_123", type: "like", // Optionally override existing reaction enforce_unique: true, }); await client.deleteCommentReaction({ id: "comment_123", type: "like", });// 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');// Add a reaction to a comment const response = await client.feeds.addCommentReaction({ id: "comment_123", type: "like", user_id: "<user id>", // Optionally override existing reaction enforce_unique: true, }); await client.feeds.deleteCommentReaction({ id: "comment_123", type: "like", user_id: "<user id>", });// Add comment reaction _, err = client.Feeds().AddCommentReaction(context.Background(), commentID, &getstream.AddCommentReactionRequest{ Type: "like", UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error adding comment reaction:", err) } // Delete comment reaction _, err = client.Feeds().DeleteCommentReaction(context.Background(), commentID, "like", &getstream.DeleteCommentReactionRequest{ UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error deleting comment reaction:", err) }Map<String, Object> filter = new HashMap<>(); filter.put("object_id", activityId); QueryCommentsRequest queryRequest = QueryCommentsRequest.builder().filter(filter).limit(10).build(); QueryCommentsResponse response = feeds.queryComments(queryRequest).execute().getData();// Add a reaction to a comment $response = $feedsClient->addCommentReaction( $response->getData()->comment->id, new GeneratedModels\AddCommentReactionRequest( type: 'like', userID: 'user123', // Optionally override existing reaction enforceUnique: true ) ); // Remove a reaction from a comment $response = $feedsClient->deleteCommentReaction( $response->getData()->comment->id, 'like', userID: 'user123' ); var response = await _feedsV3Client.QueryCommentsAsync( new QueryCommentsRequest { Filter = new Dictionary<string, object> { ["object_id"] = activityId }, Limit = 10 } );response = self.client.feeds.query_comments( filter={"object_id": activity_id}, limit=10 )# Query comments for an activity query_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { object_id: activity_id }, limit: 10 ) response = client.feeds.query_comments(query_request) # Search in comment texts search_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { comment_text: { '$q' => 'oat' } } ) response = client.feeds.query_comments(search_request) # Comments from a specific user user_comments_request = GetStream::Generated::Models::QueryCommentsRequest.new( filter: { user_id: 'user123' }, limit: 20 ) response = client.feeds.query_comments(user_comments_request)Comment Threading
let commentList = client.activityCommentList( for: .init( objectId: "activity_123", objectType: "activity", depth: 3, limit: 20 ) ) let comments = try await commentList.get() // Get replies of a specific parent comment let replyList = client.commentReplyList( for: .init( commentId: "parent_123" ) ) let replies = try await replyList.get()val commentList = client.activityCommentList( query = ActivityCommentsQuery( objectId = "activity_123", objectType = "activity", depth = 3, limit = 20 ) ) val comments: Result<List<ThreadedCommentData>> = commentList.get() // Get replies of a specific parent comment val replyList = client.commentReplyList( query = CommentRepliesQuery( commentId = "parent_123" ) ) val replies: Result<List<ThreadedCommentData>> = replyList.get()await feed.getOrCreate(); // To store comments in feed state you can use the loadNextPageActivityComments and loadNextPageCommentReplies const activity = feed.state.getLatestValue().activities?.[0]!; await feed.loadNextPageActivityComments(activity, { limit: 20 }); const commentState = feed.state.getLatestValue()?.comments_by_entity_id[activity.id]; const parentComment = commentState?.comments?.[0]!; const firstPageOfReplies = feed.state.getLatestValue()?.comments_by_entity_id[parentComment?.id]; // Load next page of replies (or first, if replies aren't yet initialized) feed.loadNextPageCommentReplies(parentComment); // To read comments without storing them in state use getComments and getCommentReplies const response = client.getComments({ object_id: 'activity_123', object_type: 'activity', // Depth of the threaded comments depth: 3, limit: 20, }); // Get replies of a specific parent comment const response = client.getCommentReplies({ id: '<parent id>', });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();const response = client.feeds.getComments({ object_id: "activity_123", object_type: "activity", // Depth of the threaded comments depth: 3, limit: 20, }); // Get replies of a specific parent comment const response = client.feeds.getCommentReplies({ id: "<parent id>", });// Get comments for an activity _, err = client.Feeds().GetComments(context.Background(), &getstream.GetCommentsRequest{ ObjectID: "activity_123", ObjectType: "activity", // Depth of the threaded comments Depth: getstream.PtrTo(3), Limit: getstream.PtrTo(20), }) if err != nil { log.Fatal("Error getting comments:", err) } // Get replies of a specific parent comment _, err = client.Feeds().GetCommentReplies(context.Background(), parentID, &getstream.GetCommentRepliesRequest{}) if err != nil { log.Fatal("Error getting comment replies:", err) }DeleteCommentRequest deleteRequest = DeleteCommentRequest.builder().build(); DeleteCommentResponse response = feeds.deleteComment(commentId, deleteRequest).execute().getData();// Get comments for an activity with threading // activity id, object type, depth, sort, replies limit, limit, prev, next $response = $feedsClient->getComments('activity_123', 'activity', 3, 'best', 20, 20, '', ''); // Get replies of a specific parent comment // parent id, depth, sort, replies limit, limit, prev, next $response = $feedsClient->getCommentReplies('parent_123', 3, 'best', 20, 20, '', '');var response = await _feedsV3Client.DeleteCommentAsync( commentId, new { user_id = _testUserId } );response = self.client.feeds.delete_comment( comment_id, hard_delete=False ) # soft delete# Delete a comment (soft delete) response = client.feeds.delete_comment(comment_id, hard_delete: false)