// Adding a comment to an activity
let comment = try await feed.addComment(
request: .init(
id: "comment_123", // id is optional, but must be unique. will be auto-generated if not provided
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!",
parentId: "comment_456"
)
)
// Adding a comment with attachments
let commentWithAttachment = try await feed.addComment(
request: .init(
comment: "Check out this image!",
objectId: "activity_123",
objectType: "activity",
attachments: [
Attachment(
imageUrl: "https://example.com/image.jpg",
type: "image"
)
]
)
)Comments
Comments support voting, ranking, threading, images, URL previews, mentions and notifications.
Adding Comments
AddCommentRequest commentRequest =
AddCommentRequest.builder()
.id("comment_123") // id is optional, but must be unique. will be auto-generated if not provided
.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 with attachments
AddCommentRequest commentWithAttachmentRequest =
AddCommentRequest.builder()
.comment("Check out this image!")
.objectID(activityId)
.objectType("activity")
.userID(testUserId)
.attachments(List.of(
Attachment.builder()
.imageUrl("https://example.com/image.jpg")
.type("image")
.build()))
.build();
AddCommentResponse attachmentResponse = feeds.addComment(commentWithAttachmentRequest).execute().getData();You can use Stream's CDN for storing and quickly accessing files attached to comments.
Comment request options
AddCommentRequest
| Name | Type | Description | Constraints |
|---|---|---|---|
attachments | Attachment[] | Media attachments for the reply | - |
comment | string | Text content of the comment | - |
copy_custom_to_notification | boolean | Whether to copy custom data to the notification activity (only applies when create_notification_activity is true) | - |
create_notification_activity | boolean | Whether to create a notification activity for this comment | - |
custom | object | Custom data for the comment | - |
id | string | Optional custom ID for the comment (max 255 characters). If not provided, a UUID will be generated. | - |
mentioned_user_ids | string[] | List of users mentioned in the reply | - |
object_id | string | ID of the object to comment on. Required for root comments | - |
object_type | string | Type of the object to comment on. Required for root comments | - |
parent_id | string | ID of parent comment for replies. When provided, object_id and object_type are automatically inherited from the parent comment. | - |
skip_enrich_url | boolean | Whether to skip URL enrichment for this comment | - |
skip_push | boolean | - | - |
user | UserRequest | - | - |
user_id | string | - | - |
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.
UpdateCommentRequest updateRequest =
UpdateCommentRequest.builder().comment("Updated comment text from Java SDK").build();
UpdateCommentResponse response =
feeds.updateComment(commentId, updateRequest).execute().getData();
System.out.println("Comment edited at: " + response.getComment().getEditedAt());Removing Comments
DeleteCommentRequest deleteRequest = DeleteCommentRequest.builder().build();
DeleteCommentResponse response =
feeds.deleteComment(commentId, deleteRequest).execute().getData();Reading Comments
You'll also want to show/return these comments. The most important is when reading the feed.
GetOrCreateFeedResponse feedResponse = feeds.getOrCreateFeed(...).execute().getData();
var comments = feedResponse.getData().getActivities().get(0).getComments();
// Reading a single comment
GetCommentResponse commentResponse = feeds.getComment("123").execute().getData();Sort options
The following sort options are supported when reading comments:
last: newest comment returned firstfirst: oldest comment returned firsttop: highest score returned first - computed fromupvote-downvotereaction typescontroversial: controversial comment returned first - mixed reactions (upvoteanddownvote) and lots of commentsbest: 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
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();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_atscore: same astopsort optionconfidence_score- same asbestsort optioncontroversy_score- same ascontroversialsort optionupvote_countdownvote_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.
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();Overview of the reaction model
FeedsReactionResponse
| Name | Type | Description | Constraints |
|---|---|---|---|
activity_id | string | ID of the activity that was reacted to | Required |
comment_id | string | ID of the comment that was reacted to | - |
created_at | number | When the reaction was created | Required |
custom | object | Custom data for the reaction | - |
type | string | Type of reaction | Required |
updated_at | number | When the reaction was last updated | Required |
user | UserResponse | User who created the reaction | Required |
Comment Threading
DeleteCommentRequest deleteRequest = DeleteCommentRequest.builder().build();
DeleteCommentResponse response =
feeds.deleteComment(commentId, deleteRequest).execute().getData();Reading comment replies supports the same sort parameters 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
The activity author is always allowed to add comments regardless of the reply settings.
AddActivityRequest activity =
AddActivityRequest.builder()
.type("post")
.feeds(List.of(testFeedId))
.text("apple stock will go up")
.userID(testUserId)
.restrictReplies(RestrictReplies.PEOPLE_I_FOLLOW) // Options: EVERYONE, PEOPLE_I_FOLLOW, NOBODY
.build();
AddActivityResponse response = feeds.addActivity(activity).execute().getData();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:
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);own_followings is only set when reading a feed/activity from client-side, for server-side requests it will be empty.
- When fetching a single activity,
own_followingsis set by default - When reading a feed, you have to explicitly enable fetching
own_followings:
feed.getOrCreate({ enrichment_options: { enrich_own_followings: true } });Overview of the comment model
CommentResponse
| Name | Type | Description | Constraints |
|---|---|---|---|
attachments | Attachment[] | Attachments associated with the comment | - |
confidence_score | number | Confidence score of the comment | Required |
controversy_score | number | Controversy score of the comment | - |
created_at | number | When the comment was created | Required |
custom | object | Custom data for the comment | - |
deleted_at | number | When the comment was deleted | - |
downvote_count | integer | Number of downvotes for this comment | Required |
edited_at | number | When the comment was last edited | - |
id | string | Unique identifier for the comment | Required |
latest_reactions | FeedsReactionResponse[] | Recent reactions to the comment | - |
mentioned_users | UserResponse[] | Users mentioned in the comment | Required |
moderation | ModerationV2Response | Moderation details for the comment | - |
object_id | string | ID of the object this comment is associated with | Required |
object_type | string | Type of the object this comment is associated with | Required |
own_reactions | FeedsReactionResponse[] | Current user's reactions to this activity | Required |
parent_id | string | ID of parent comment for nested replies | - |
reaction_count | integer | Number of reactions to this comment | Required |
reaction_groups | object | Grouped reactions by type | - |
reply_count | integer | Number of replies to this comment | Required |
score | integer | Score of the comment based on reactions | Required |
status | string (active, deleted, removed, hidden, shadow_blocked) | Status of the comment. One of: active, deleted, removed, hidden | Required |
text | string | Text content of the comment | - |
updated_at | number | When the comment was last updated | Required |
upvote_count | integer | Number of upvotes for this comment | Required |
user | UserResponse | User who created the comment | Required |
Add comments in batch
AddCommentsBatchRequest batchRequest = AddCommentsBatchRequest.builder()
.comments(List.of(
AddCommentRequest.builder()
.id("comment_123") // id is optional, but must be unique. will be auto-generated if not provided
.comment("So great!")
.objectID(activityId)
.objectType("activity")
.userID(testUserId)
.custom(Map.of("sentiment", "positive"))
.build()
))
.build();
AddCommentsBatchResponse response = feeds.addCommentsBatch(batchRequest).execute().getData();