# Notification Feeds

Notification feeds let you notify users about relevant interactions, for example

- someone started to follow them
- someone liked their post
- someone left a comment on their post

## Creating notification feeds

The built-in `notification` feed comes with the necessary configurations, but it's also possible to create your own notification feed group:

<partial id="activity-feeds/v3-latest/_default/_partials/custom-notification-group"></partial>

### Notification configuration

The notification config includes several settings that control how notifications are tracked and deduplicated:

- **TrackSeen**: When enabled, tracks which notifications have been seen by the user
- **TrackRead**: When enabled, tracks which notifications have been read by the user
- **DeduplicationWindow**: Controls how duplicate notifications are handled (only available for the built-in `notification` feed group)
  - Empty string (`""`) = always deduplicate (default behavior)
  - Duration string (e.g., `"24h"`, `"7d"`) = time-based deduplication window

<admonition type="info">

**Note:** Comments are not deduplicated. Each comment will create a separate notification activity, regardless of the deduplication window setting.

</admonition>

The built-in `notification` feed group has deduplication enabled by default (always deduplicate). To change the deduplication window, you need to update the `notification` feed group.

### Aggregation format

The built-in `notification` feed uses the following aggregation format: `"{{ target_id }}_{ type }}_{{ time.strftime('%Y-%m-%d') }}"`. You can change this syntax by updating the `notification` feed group.

You can see all supported fields and syntax for aggregation in the [Aggregation guide](/activity-feeds/docs/<framework>/aggregation/).

It's possible to turn off aggregation, but still enable notification tracking. In that case every new activity will increase `unread`/`unseen` count. When you have aggregation turned on, `unread`/`unseen` will refer to the number of aggregated groups.

### Adding notification activities

The built-in `notification` groups can automatically create notifications for the most common interactions (see [Built-in notification feed section](#built-in-notification-feed)).

If you want to extend that, or create your own notification feed, you can add notification activities using server-side integration. You can add webhook handlers for the relevant events to create notifications without API calls from your client-side application to your server-side application.

It's important to note that `target_id` is only defined if a notification is created by Stream API. If you want to extend or replace this behavior by adding notification activities from your own application, you most likely need to extend the default aggregation format. You can see all supported fields and syntax for aggregation in the [Aggregation guide](/activity-feeds/docs/<framework>/aggregation/).

### Manual Activity Addition to Notification Feeds

You can directly add activities to notification feeds for complete control over notifications (only available server-side):

<partial id="activity-feeds/v3-latest/_default/_partials/custom-notification-activity"></partial>

**Important:** When adding activities directly to notification feeds, ensure the activity `type` is included in the feed group's `push_types` configuration to trigger push notifications.

## Built-in notification feed

### Creating notification activities

The built-in `notification` feed allows you to automatically create notification activities. The following actions are supported and will automatically create notification activities for the target user depending on the action.

| Action                             | Trigger User                                          | Target User (Recipient)           | Notification Type  | Notification Text                     | Deduplicated? | Notes                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------- | ----------------------------------------------------- | --------------------------------- | ------------------ | ------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **React to Activity**              | User who reacts (e.g., Bob)                           | Activity author (e.g., Alice)     | `reaction`         | `{user} reacted to your activity`     | ✅ Yes        | Multiple reactions from the same user on the same activity are deduplicated within the deduplication window                                                                                                                                                                                                                                                                                      |
| **React to Comment**               | User who reacts (e.g., Charlie)                       | Comment author (e.g., Bob)        | `comment_reaction` | `{user} reacted to your comment`      | ✅ Yes        | Multiple reactions from the same user on the same comment are deduplicated within the deduplication window. The activity author does NOT receive a notification for reactions                                                                                                                                                                                                                    |
| **Comment on Activity**            | User who comments (e.g., Bob)                         | Activity author (e.g., Alice)     | `comment`          | `{user} commented on your activity`   | ❌ No         | Each comment creates a new notification; not deduplicated                                                                                                                                                                                                                                                                                                                                        |
| **Reply to Comment**               | User who replies (e.g., Charlie)                      | Comment author (e.g., Bob)        | `comment_reply`    | `{user} replied to your comment`      | ❌ No         | Each reply creates a new notification; not deduplicated. The activity author does NOT receive a notification for replies                                                                                                                                                                                                                                                                         |
| **Follow User**                    | User who follows (e.g., Bob)                          | User being followed (e.g., Alice) | `follow`           | `{user} started following you`        | ✅ Yes        | Multiple follows/unfollows from the same user are deduplicated within the deduplication window                                                                                                                                                                                                                                                                                                   |
| **Mention in Activity**            | User who creates activity with mention (e.g., Alice)  | Mentioned user (e.g., Bob)        | `mention`          | `{user} mentioned you in an activity` | ✅ Yes        | Multiple mentions from the same user on the same activity are deduplicated within the deduplication window                                                                                                                                                                                                                                                                                       |
| **Mention in Comment**             | User who creates comment with mention (e.g., Charlie) | Mentioned user (e.g., Bob)        | `comment_mention`  | `{user} mentioned you in a comment`   | ✅ Yes        | Multiple mentions from the same user on the same comment are deduplicated within the deduplication window. The activity author does NOT receive a notification for mentions (they already get a comment notification)                                                                                                                                                                            |
| **Update Activity (add mentions)** | User who updates activity (e.g., Alice)               | Mentioned user (e.g., Bob)        | `mention`          | `{user} mentioned you in an activity` | ✅ Yes        | When mentions are added via `UpdateActivity` or `UpdateActivityPartial` with `handle_mention_notifications=true`, `mention` notifications are automatically created for newly mentioned users. Multiple mentions from the same user on the same activity are deduplicated within the deduplication window                                                                                        |
| **Update Comment (add mentions)**  | User who updates comment (e.g., Charlie)              | Mentioned user (e.g., Bob)        | `comment_mention`  | `{user} mentioned you in a comment`   | ✅ Yes        | When mentions are added via `UpdateComment` with `handle_mention_notifications=true`, `comment_mention` notifications are automatically created for newly mentioned users. Multiple mentions from the same user on the same comment are deduplicated within the deduplication window. The activity author does NOT receive a notification for mentions (they already get a comment notification) |

<admonition type="info">

Adding notifications with the create notification activity flag only works if the target user (the one who should receive the notification) has a feed with group `notification`, and id `<user id>`.

</admonition>

<codetabs>

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

```kotlin
// Eric follows Jane
ericFeed.follow(
    targetFid = janeFeed.fid,
    createNotificationActivity = true // When true Jane's notification feed will be updated with follow activity
)

// Eric comments on Jane's activity
ericFeed.addComment(
    ActivityAddCommentRequest(
        comment = "Agree!",
        activityId = janeActivity.activityId,
        createNotificationActivity = true // When true Jane's notification feed will be updated with comment activity
    )
)

// Eric reacts to Jane's activity
ericFeed.addReaction(
    activityId = janeActivity.activityId,
    request = AddReactionRequest(
        type = "like",
        createNotificationActivity = true // When true Jane's notification feed will be updated with reaction activity
    ),
)

// Eric reacts to a comment posted to Jane's activity by Sara
ericFeed.addCommentReaction(
    commentId = saraComment.id,
    request = AddCommentReactionRequest(
        type = "like",
        createNotificationActivity = true // When true Sara's notification feed will be updated with comment reaction activity
    ),
)
```

</codetabs-item>

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

```js
// Eric follows Jane
await ericTimeline.follow(janeFeed, {
  // When true Jane's notification feed will be updated with follow activity
  create_notification_activity: true,
});

// Eric comments on Jane's activity
await ericClient.addComment({
  comment: "Agree!",
  object_id: janeActivity.id,
  object_type: "activity",
  // When true Jane's notification feed will be updated with comment activity
  create_notification_activity: true,
});

// Eric reacts to Jane's activity
await ericClient.addReaction({
  activity_id: janeActivity.id,
  // When true Jane's notification feed will be updated with reaction activity
  type: "like",
  create_notification_activity: true,
});

// Eric reacts to a comment posted to Jane's activity by Sara
await ericClient.addCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true Sara's notification feed will be updated with comment reaction activity
  create_notification_activity: true,
});
```

</codetabs-item>

<codetabs-item value="react" label="React">

```js
// Eric follows Jane
await ericTimeline.follow(janeFeed, {
  // When true Jane's notification feed will be updated with follow activity
  create_notification_activity: true,
});

// Eric comments on Jane's activity
await ericClient.addComment({
  comment: "Agree!",
  object_id: janeActivity.id,
  object_type: "activity",
  // When true Jane's notification feed will be updated with comment activity
  create_notification_activity: true,
});

// Eric reacts to Jane's activity
await ericClient.addReaction({
  activity_id: janeActivity.id,
  // When true Jane's notification feed will be updated with reaction activity
  type: "like",
  create_notification_activity: true,
});

// Eric reacts to a comment posted to Jane's activity by Sara
await ericClient.addCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true Sara's notification feed will be updated with comment reaction activity
  create_notification_activity: true,
});
```

</codetabs-item>

<codetabs-item value="reactnative" label="React Native">

```js
// Eric follows Jane
await ericTimeline.follow(janeFeed, {
  // When true Jane's notification feed will be updated with follow activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy follow custom data to the notification activity
});

// Eric comments on Jane's activity
await ericClient.addComment({
  comment: "Agree!",
  object_id: janeActivity.id,
  object_type: "activity",
  // When true Jane's notification feed will be updated with comment activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy comment custom data to the notification activity
});

// Eric reacts to Jane's activity
await ericClient.addReaction({
  activity_id: janeActivity.id,
  // When true Jane's notification feed will be updated with reaction activity
  type: "like",
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy reaction custom data to the notification activity
});

// Eric reacts to a comment posted to Jane's activity by Sara
await ericClient.addCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true Sara's notification feed will be updated with comment reaction activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy comment reaction custom data to the notification activity
});
```

</codetabs-item>

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

```dart
// Eric follows Jane
await ericFeed.follow(
  targetFid: janeFeed.fid,
  createNotificationActivity:
      true, // When true Jane's notification feed will be updated with follow activity
);
// Eric comments on Jane's activity
await ericFeed.addComment(
  request: ActivityAddCommentRequest(
    comment: 'Agree!',
    activityId: janeActivity.activityId,
    createNotificationActivity:
        true, // When true Jane's notification feed will be updated with comment activity
  ),
);
// Eric reacts to Jane's activity
await ericFeed.addActivityReaction(
  activityId: janeActivity.activityId,
  request: const AddReactionRequest(
    type: 'like',
    createNotificationActivity: true, // When true Jane's notification feed will be updated with reaction activity
  ),
);
// Eric reacts to a comment posted to Jane's activity by Sara
await ericFeed.addCommentReaction(
  commentId: saraComment.activityId,
  request: const AddCommentReactionRequest(
    type: 'like',
    createNotificationActivity:
        true, // When true Sara's notification feed will be updated with comment reaction activity
  ),
);
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
// Eric follows Jane
await serverClient.feeds.follow({
  source: ericTimeline.feed,
  target: janeFeed.feed,
  // When true Jane's notification feed will be updated with follow activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy follow custom data to the notification activity
});

// Eric comments on Jane's activity
await serverClient.feeds.addComment({
  comment: "Agree!",
  object_id: janeActivity.id,
  object_type: "activity",
  // When true Jane's notification feed will be updated with comment activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy comment custom data to the notification activity
  user_id: "eric",
});

// Eric reacts to Jane's activity
await serverClient.feeds.addReaction({
  activity_id: janeActivity.id,
  // When true Jane's notification feed will be updated with reaction activity
  type: "like",
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy reaction custom data to the notification activity
  user_id: "eric",
});

// Eric reacts to a comment posted to Jane's activity by Sara
await serverClient.feeds.addCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true Sara's notification feed will be updated with comment reaction activity
  create_notification_activity: true,
  copy_custom_to_notification: true, // Copy comment reaction custom data to the notification activity
  user_id: "eric",
});
```

</codetabs-item>

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

```go
ctx := context.Background()

// Eric follows Jane
_, err = client.Feeds().Follow(ctx, &getstream.FollowRequest{
  Source:                     "user:eric",
  Target:                     "user:jane",
  CreateNotificationActivity: getstream.PtrTo(true), // When true Jane's notification feed will be updated with follow activity
})
if err != nil {
  log.Fatal("Error following user:", err)
}

// Eric comments on Jane's activity
_, err = client.Feeds().AddComment(ctx, &getstream.AddCommentRequest{
  Comment:                    "Agree!",
  ObjectID:                   "janeActivity.id", // This would be the actual activity ID
  ObjectType:                 "activity",
  CreateNotificationActivity: getstream.PtrTo(true), // When true Jane's notification feed will be updated with comment activity
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error adding comment:", err)
}

// Eric reacts to Jane's activity
_, err = client.Feeds().AddReaction(ctx, "janeActivity.id", &getstream.AddReactionRequest{ // This would be the actual activity ID
  Type:                       "like",
  CreateNotificationActivity: getstream.PtrTo(true), // When true Jane's notification feed will be updated with reaction activity
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error adding reaction:", err)
}

// Eric reacts to a comment posted to Jane's activity by Sara
_, err = client.Feeds().AddCommentReaction(ctx, "saraComment.id", &getstream.AddCommentReactionRequest{ // This would be the actual comment ID
  Type:                       "like",
  CreateNotificationActivity: getstream.PtrTo(true), // When true Sara's notification feed will be updated with comment reaction activity
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error adding comment reaction:", err)
}
```

</codetabs-item>

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

```php
use GetStream\GeneratedModels;

// Eric follows Jane
$feedsClient->follow(new GeneratedModels\FollowRequest(
    source: "user:eric",
    target: "user:jane",
    createNotificationActivity: true // When true Jane's notification feed will be updated with follow activity
));

// Eric comments on Jane's activity
$feedsClient->addComment(new GeneratedModels\AddCommentRequest(
    comment: "Agree!",
    objectID: "janeActivity.id", // This would be the actual activity ID
    objectType: "activity",
    createNotificationActivity: true, // When true Jane's notification feed will be updated with comment activity
    userID: "eric"
));

// Eric reacts to Jane's activity
$feedsClient->addActivityReaction("janeActivity.id", new GeneratedModels\AddReactionRequest( // This would be the actual activity ID
    type: "like",
    createNotificationActivity: true, // When true Jane's notification feed will be updated with reaction activity
    userID: "eric"
));

// Eric reacts to a comment posted to Jane's activity by Sara
$feedsClient->addCommentReaction("saraComment.id", new GeneratedModels\AddCommentReactionRequest( // This would be the actual comment ID
    type: "like",
    createNotificationActivity: true, // When true Sara's notification feed will be updated with comment reaction activity
    userID: "eric"
));
```

</codetabs-item>

</codetabs>

### Updating mentions in activities and comments

You can also create or remove mention notifications when updating activities or comments. This flag defaults to `false` for all endpoints it's supported in.

<codetabs>

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

```kotlin
// Alice updates her activity to mention Bob
ericFeed.updateActivity(
    activityId = activityId,
    text = "Hey @Bob check this out!",
    mentionedUserIds = listOf("bob"),
    handleMentionNotifications = true // When true, Bob will receive a mention notification
)

// Alice updates her comment to mention Charlie
ericFeed.updateComment(
    commentId = commentId,
    comment = "Hey @Charlie!",
    mentionedUserIds = listOf("charlie"),
    handleMentionNotifications = true // When true, Charlie will receive a comment_mention notification
)

// Alice removes mentions from her activity
ericFeed.updateActivity(
    activityId = activityId,
    text = "Updated text without mentions",
    mentionedUserIds = emptyList(),
    handleMentionNotifications = true // When true, mention notifications for removed users are deleted
)
```

</codetabs-item>

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

```js
// Alice updates her activity to mention Bob
await ericClient.updateActivity({
  id: activityId,
  text: "Hey @Bob check this out!",
  mentioned_user_ids: ["bob"],
  handle_mention_notifications: true, // When true, Bob will receive a mention notification
});

// Alice updates her comment to mention Charlie
await ericClient.updateComment({
  id: commentId,
  comment: "Hey @Charlie!",
  mentioned_user_ids: ["charlie"],
  handle_mention_notifications: true, // When true, Charlie will receive a comment_mention notification
});

// Alice removes mentions from her activity
await ericClient.updateActivity({
  id: activityId,
  text: "Updated text without mentions",
  mentioned_user_ids: [],
  handle_mention_notifications: true, // When true, mention notifications for removed users are deleted
});
```

</codetabs-item>

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

```dart
// Alice updates her activity to mention Bob
await ericFeed.updateActivity(
  activityId: activityId,
  request: UpdateActivityRequest(
    text: "Hey @Bob check this out!",
    mentionedUserIDs: ["bob"],
    handleMentionNotifications: true, // When true, Bob will receive a mention notification
  ),
);

// Alice updates her comment to mention Charlie
await ericFeed.updateComment(
  commentId: commentId,
  request: UpdateCommentRequest(
    comment: "Hey @Charlie!",
    mentionedUserIDs: ["charlie"],
    handleMentionNotifications: true, // When true, Charlie will receive a comment_mention notification
  ),
);

// Alice removes mentions from her activity
await ericFeed.updateActivity(
  activityId: activityId,
  request: UpdateActivityRequest(
    text: "Updated text without mentions",
    mentionedUserIDs: [],
    handleMentionNotifications: true, // When true, mention notifications for removed users are deleted
  ),
);
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
// Alice updates her activity to mention Bob
await serverClient.feeds.updateActivity({
  id: activityId,
  text: "Hey @Bob check this out!",
  mentioned_user_ids: ["bob"],
  handle_mention_notifications: true, // When true, Bob will receive a mention notification
  user_id: "alice",
});

// Alice updates her comment to mention Charlie
await serverClient.feeds.updateComment({
  id: commentId,
  comment: "Hey @Charlie!",
  mentioned_user_ids: ["charlie"],
  handle_mention_notifications: true, // When true, Charlie will receive a comment_mention notification
  user_id: "alice",
});

// Alice removes mentions from her activity
await serverClient.feeds.updateActivity({
  id: activityId,
  text: "Updated text without mentions",
  mentioned_user_ids: [],
  handle_mention_notifications: true, // When true, mention notifications for removed users are deleted
  user_id: "alice",
});
```

</codetabs-item>

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

```go
ctx := context.Background()

// Alice updates her activity to mention Bob
_, err = client.Feeds().UpdateActivity(ctx, activityId, &getstream.UpdateActivityRequest{
  Text:                       "Hey @Bob check this out!",
  MentionedUserIDs:           []string{"bob"},
  HandleMentionNotifications: getstream.PtrTo(true), // When true, Bob will receive a mention notification
  UserID:                     getstream.PtrTo("alice"),
})
if err != nil {
  log.Fatal("Error updating activity:", err)
}

// Alice updates her comment to mention Charlie
_, err = client.Feeds().UpdateComment(ctx, commentId, &getstream.UpdateCommentRequest{
  Comment:                    "Hey @Charlie!",
  MentionedUserIDs:           getstream.PtrTo([]string{"charlie"}),
  HandleMentionNotifications: getstream.PtrTo(true), // When true, Charlie will receive a comment_mention notification
  UserID:                     getstream.PtrTo("alice"),
})
if err != nil {
  log.Fatal("Error updating comment:", err)
}

// Alice removes mentions from her activity
_, err = client.Feeds().UpdateActivity(ctx, activityId, &getstream.UpdateActivityRequest{
  Text:                       "Updated text without mentions",
  MentionedUserIDs:           []string{},
  HandleMentionNotifications: getstream.PtrTo(true), // When true, mention notifications for removed users are deleted
  UserID:                     getstream.PtrTo("alice"),
})
if err != nil {
  log.Fatal("Error updating activity:", err)
}
```

</codetabs-item>

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

```php
use GetStream\GeneratedModels;

// Alice updates her activity to mention Bob
$feedsClient->updateActivity(activityId, new GeneratedModels\UpdateActivityRequest(
    text: "Hey @Bob check this out!",
    mentionedUserIDs: ["bob"],
    handleMentionNotifications: true, // When true, Bob will receive a mention notification
    userID: "alice"
));

// Alice updates her comment to mention Charlie
$feedsClient->updateComment(commentId, new GeneratedModels\UpdateCommentRequest(
    comment: "Hey @Charlie!",
    mentionedUserIDs: ["charlie"],
    handleMentionNotifications: true, // When true, Charlie will receive a comment_mention notification
    userID: "alice"
));

// Alice removes mentions from her activity
$feedsClient->updateActivity(activityId, new GeneratedModels\UpdateActivityRequest(
    text: "Updated text without mentions",
    mentionedUserIDs: [],
    handleMentionNotifications: true, // When true, mention notifications for removed users are deleted
    userID: "alice"
));
```

</codetabs-item>

</codetabs>

<admonition type="info">

Commenting and reacting to your own activities and comments will not create notification activities.

</admonition>

### Deleting notification activities

When you add notification activities with `create_notification_activity` you can also have the API automatically remove these when the corresponding trigger entity is deleted.
This is done by using the flag `delete_notification_activity` which defaults to `false` for all endpoints it's supported in.

| Action                                | Notification Type Deleted | Notes                                                                                                                                                                                                          |
| ------------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Remove Activity Reaction**          | `reaction`                | Only the notification activity created by the user removing the reaction is deleted. Other users' reaction notifications remain unaffected.                                                                    |
| **Remove Comment Reaction**           | `comment_reaction`        | Only the notification activity created by the user removing the reaction is deleted. Other users' comment reaction notifications remain unaffected.                                                            |
| **Delete Comment**                    | `comment`                 | Deletes the comment notification for the activity author.                                                                                                                                                      |
| **Delete Comment**                    | `comment_mention`         | When a comment with mentions is deleted, `comment_mention` notifications are deleted for all mentioned users if `delete_notification_activity=true`.                                                           |
| **Unfollow User**                     | `follow`                  | Only the notification activity created by the user performing the unfollow is deleted.                                                                                                                         |
| **Delete Activity**                   | `mention`                 | When an activity with mentions is deleted, `mention` notifications are deleted for all mentioned users if `delete_notification_activity=true`.                                                                 |
| **Delete Activities (batch)**         | `mention`                 | When multiple activities with mentions are deleted via `DeleteActivities` with `delete_notification_activity=true`, `mention` notifications are deleted for all mentioned users across all deleted activities. |
| **Update Activity (remove mentions)** | `mention`                 | When mentions are removed via `UpdateActivity` or `UpdateActivityPartial` with `handle_mention_notifications=true`, `mention` notifications are automatically removed for users no longer mentioned.           |
| **Update Comment (remove mentions)**  | `comment_mention`         | When mentions are removed via `UpdateComment` with `handle_mention_notifications=true`, `comment_mention` notifications are automatically removed for users no longer mentioned.                               |

<admonition type="info">

**Deletion Scope:** The deletion behavior differs depending on the action:

- **Reactions and Follows:** Only the notification activity created by the specific user performing the deletion is removed. Other users' notifications remain unaffected.
- **Activities and Comments with Mentions:** When an activity or comment containing mentions is deleted, notification activities are removed for **all** mentioned users if `delete_notification_activity=true`.

</admonition>

<codetabs>

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

```kotlin
// Eric unfollows Jane
ericFeed.unfollow(
    targetFid = janeFeed.fid,
    // When true the corresponding notification activity will be removed from Jane's notification feed
    deleteNotificationActivity = true
)

// Eric removes his comment
ericFeed.deleteComment(
    commentId = commentId,
    // When true the corresponding notification activity will be removed from Jane's notification feed
    deleteNotificationActivity = true
)

// Eric removes his activity reaction
ericFeed.deleteReaction(
    activityId = janeActivity.activityId,
    type = "like",
    // When true the corresponding notification activity will be removed from Jane's notification feed
    deleteNotificationActivity = true
)

// Eric removes his comment reaction
ericFeed.deleteCommentReaction(
    commentId = saraComment.id,
    type = "like",
    // When true the corresponding notification activity will be removed from Jane's notification feed
    deleteNotificationActivity = true
)

// Eric deletes his activity with mentions
ericFeed.deleteActivity(
    activityId = activityId,
    // When true, mention notifications for all mentioned users will be removed
    deleteNotificationActivity = true
)

// Eric deletes multiple activities with mentions (batch operation)
ericFeed.deleteActivities(
    activityIds = listOf(activityId1, activityId2),
    // When true, mention notifications for all mentioned users will be removed
    deleteNotificationActivity = true
)
```

</codetabs-item>

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

```js
// Eric unfollows Jane
await ericTimeline.unfollow(janeFeed, {
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
});

// Eric removes his comment
await ericClient.deleteComment({
  id: commentId,
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
});

// Eric removes his activity reaction
await ericClient.deleteActivityReaction({
  activity_id: janeActivity.id,
  type: "like",
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
});

// Eric removes his comment reaction
await ericClient.deleteCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
});

// Eric deletes his activity with mentions
await ericClient.deleteActivity({
  id: activityId,
  // When true, mention notifications for all mentioned users will be removed
  delete_notification_activity: true,
});

// Eric deletes multiple activities with mentions (batch operation)
await ericClient.deleteActivities({
  ids: [activityId1, activityId2],
  // When true, mention notifications for all mentioned users will be removed
  delete_notification_activity: true,
});
```

</codetabs-item>

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

```dart
// Eric unfollows Jane
await ericFeed.unfollow(
  targetFid: janeFeed.fid,
  // When true the corresponding notification activity will be removed from Jane's notification feed
  deleteNotificationActivity: true,
);

// Eric removes his comment
await ericFeed.deleteComment(
  commentId: commentId,
  // When true the corresponding notification activity will be removed from Jane's notification feed
  deleteNotificationActivity: true,
);

// Eric removes his activity reaction
await ericFeed.deleteActivityReaction(
  activityId: janeActivity.activityId,
  type: 'like',
  // When true the corresponding notification activity will be removed from Jane's notification feed
  deleteNotificationActivity: true,
);

// Eric removes his comment reaction
await ericFeed.deleteCommentReaction(
  commentId: saraComment.id,
  type: 'like',
  // When true the corresponding notification activity will be removed from Jane's notification feed
  deleteNotificationActivity: true,
);

// Eric deletes his activity with mentions
await ericFeed.deleteActivity(
  activityId: activityId,
  // When true, mention notifications for all mentioned users will be removed
  deleteNotificationActivity: true,
);

// Eric deletes multiple activities with mentions (batch operation)
await ericFeed.deleteActivities(
  activityIds: [activityId1, activityId2],
  // When true, mention notifications for all mentioned users will be removed
  deleteNotificationActivity: true,
);
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
// Eric unfollows Jane
await serverClient.feeds.unfollow({
  source: ericTimeline.feed,
  target: janeFeed.feed,
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
});

// Eric removes his comment
await serverClient.feeds.deleteComment({
  id: commentId,
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
  user_id: "eric",
});

// Eric removes his activity reaction
await serverClient.feeds.deleteActivityReaction({
  activity_id: janeActivity.id,
  type: "like",
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
  user_id: "eric",
});

// Eric removes his comment reaction
await serverClient.feeds.deleteCommentReaction({
  id: saraComment.id,
  type: "like",
  // When true the corresponding notification activity will be removed from Jane's notification feed
  delete_notification_activity: true,
  user_id: "eric",
});

// Eric deletes his activity with mentions
await serverClient.feeds.deleteActivity({
  id: activityId,
  // When true, mention notifications for all mentioned users will be removed
  delete_notification_activity: true,
  user_id: "eric",
});

// Eric deletes multiple activities with mentions (batch operation)
await serverClient.feeds.deleteActivities({
  ids: [activityId1, activityId2],
  // When true, mention notifications for all mentioned users will be removed
  delete_notification_activity: true,
  user_id: "eric",
});
```

</codetabs-item>

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

```go
ctx := context.Background()

// Eric unfollows Jane
_, err = client.Feeds().Unfollow(ctx, &getstream.UnfollowRequest{
  Source:                     "user:eric",
  Target:                     "user:jane",
  DeleteNotificationActivity: getstream.PtrTo(true), // When true the corresponding notification activity will be removed from Jane's notification feed
})
if err != nil {
  log.Fatal("Error unfollowing user:", err)
}

// Eric removes his comment
_, err = client.Feeds().DeleteComment(ctx, "commentId", &getstream.DeleteCommentRequest{ // This would be the actual comment ID
  DeleteNotificationActivity: getstream.PtrTo(true), // When true the corresponding notification activity will be removed from Jane's notification feed
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error deleting comment:", err)
}

// Eric removes his activity reaction
_, err = client.Feeds().DeleteReaction(ctx, "janeActivity.id", &getstream.DeleteReactionRequest{ // This would be the actual activity ID
  Type:                       "like",
  DeleteNotificationActivity: getstream.PtrTo(true), // When true the corresponding notification activity will be removed from Jane's notification feed
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error deleting reaction:", err)
}

// Eric removes his comment reaction
_, err = client.Feeds().DeleteCommentReaction(ctx, "saraComment.id", &getstream.DeleteCommentReactionRequest{ // This would be the actual comment ID
  Type:                       "like",
  DeleteNotificationActivity: getstream.PtrTo(true), // When true the corresponding notification activity will be removed from Jane's notification feed
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error deleting comment reaction:", err)
}

// Eric deletes his activity with mentions
_, err = client.Feeds().DeleteActivity(ctx, "activityId", &getstream.DeleteActivityRequest{ // This would be the actual activity ID
  DeleteNotificationActivity: getstream.PtrTo(true), // When true, mention notifications for all mentioned users will be removed
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error deleting activity:", err)
}

// Eric deletes multiple activities with mentions (batch operation)
_, err = client.Feeds().DeleteActivities(ctx, &getstream.DeleteActivitiesRequest{
  ActivityIDs:                []string{"activityId1", "activityId2"},
  DeleteNotificationActivity: getstream.PtrTo(true), // When true, mention notifications for all mentioned users will be removed
  UserID:                     getstream.PtrTo("eric"),
})
if err != nil {
  log.Fatal("Error deleting activities:", err)
}
```

</codetabs-item>

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

```php
use GetStream\GeneratedModels;

// Eric unfollows Jane
$feedsClient->unfollow(new GeneratedModels\UnfollowRequest(
    source: "user:eric",
    target: "user:jane",
    deleteNotificationActivity: true // When true the corresponding notification activity will be removed from Jane's notification feed
));

// Eric removes his comment
$feedsClient->deleteComment("commentId", new GeneratedModels\DeleteCommentRequest( // This would be the actual comment ID
    deleteNotificationActivity: true, // When true the corresponding notification activity will be removed from Jane's notification feed
    userID: "eric"
));

// Eric removes his activity reaction
$feedsClient->deleteActivityReaction("janeActivity.id", new GeneratedModels\DeleteReactionRequest( // This would be the actual activity ID
    type: "like",
    deleteNotificationActivity: true, // When true the corresponding notification activity will be removed from Jane's notification feed
    userID: "eric"
));

// Eric removes his comment reaction
$feedsClient->deleteCommentReaction("saraComment.id", new GeneratedModels\DeleteCommentReactionRequest( // This would be the actual comment ID
    type: "like",
    deleteNotificationActivity: true, // When true the corresponding notification activity will be removed from Jane's notification feed
    userID: "eric"
));

// Eric deletes his activity with mentions
$feedsClient->deleteActivity("activityId", new GeneratedModels\DeleteActivityRequest( // This would be the actual activity ID
    deleteNotificationActivity: true, // When true, mention notifications for all mentioned users will be removed
    userID: "eric"
));

// Eric deletes multiple activities with mentions (batch operation)
$feedsClient->deleteActivities(new GeneratedModels\DeleteActivitiesRequest(
    activityIDs: ["activityId1", "activityId2"],
    deleteNotificationActivity: true, // When true, mention notifications for all mentioned users will be removed
    userID: "eric"
));
```

</codetabs-item>

</codetabs>

### Trigger and Target

The **trigger** is the entity that triggered the creation of the notification activity. This can be a **follow**, a **reaction** or a **comment**. When the trigger is a **comment** the comment data is available on the trigger object, this allows for deep linking back to the comment that triggered the notification.

The **target** is the receiver of the trigger action. This can be a **feed** (e.g., a user's feed), an **activity** or a **comment**. When the target is an **activity** the activity data will be present in the target object. When the target is a **comment** the parent activity data and comment data will be present in the target object.

**Example:** A reply to a comment will include the data of the reply comment in the trigger and the parent comment and activity in the target.

```json
{
  "target": {
    "id": "<activity_id>",
    "type": "<activity_type>",
    "user_id": "<activity_user_id>",
    "comment": {
      "id": "<parent_comment_id>",
      "comment": "this is the parent comment",
      "user_id": "<parent_comment_user_id>"
    }
  },
  "trigger": {
    "text": "<comment_user_id> replied to your comment",
    "type": "comment_reply",
    "comment": {
      "id": "<comment_id>",
      "user_id": "<comment_user_id>",
      "comment": "this is the reply comment"
    }
  }
}
```

### Aggregating on comments and activities

By default the built-in `notification` feed aggregates on activities only with the aggregation format `{{ target_id }}-{{ type }}-{{ time.strftime('%Y-%m-%d') }}`.
If you want to aggregate on comments and activities alike you need to update the aggregation format to

```json
{% if comment_id %}
  {{ comment_id }}_{{ type }}_{{ time.strftime('%Y-%m-%d') }}
{% else %}
  {{ target_id }}_{{ type }}_{{ time.strftime('%Y-%m-%d') }}
{% endif %}
```

This lets you show notifications like

- Your comment has 5 new likes or
- Your comment has 3 new replies

### Reading notification activities

<partial id="activity-feeds/v3-latest/_default/_partials/built-in-notification-feed"></partial>

This is what Jane's notification feed looks like after the above interactions (only relevant fields shown):

- Three aggregated activity groups:
  - `<activity id>-comment-2025-08-04`
  - `<activity id>-reaction-2025-08-04`
  - `<feed id>-follow-2025-08-04`
- `notification_context` has information about the activity/action that triggered the notification
  - Please note that `notification_context` field is only defined if you're using the built-in `notification` feed and `create_notification_activity` flag

When reading notifications, every aggregated activity group contains at most 100 activities (can be configured with [aggregation group limit](/activity-feeds/docs/<framework>/aggregation/#aggregation-group-limit)). The `user_count` field is also computed from the last n activities, defined by aggregation group limit.

If a group has more activities than the limit, `user_count_truncated` will be set to `true`, signaling that `user_count` may not be accurate. This enables creating notifications like "100+ people commented on your post". The `activity_count` field is always accurate, even if the group has more activities than the limit.

Example API response:

```json
{
  aggregated_activities: [
    {
      activity_count: 1,
      user_count: 1,
      user_count_truncated: false,
      group: "activity123-comment-2025-08-04",
      activities: [
        {
          type: "comment",
          user: {
            id: "eric",
            name: "Eric",
            // other User fields
          },
          notification_context: {
            trigger: {
              text: "Eric commented on your activity",
              type: "comment",
            },
            target: {
              user_id: "jane",
              type: "post",
              text: "As earnestly shameless elsewhere defective estimable fulfilled of",
              id: "a0668408-0eb9-4906-a1cf-be79f988051d",
              attachments: [
                {
                  type: "image",
                  image_url: "https://...",
                },
              ],
            },
          },
          // Other activity fields
        },
      ],
    },
    {
      activity_count: 1,
      user_count: 1,
      group: "activity123-reaction-2025-08-04",
      activities: [
        {
          type: "reaction",
          user: {
            id: "eric",
            name: "Eric",
          },
          notification_context: {
            target: {
              id: "8966090a-30bf-4fe2-b8bc-b0fe36200e56",
              user_id: "jane",
              type: "post",
              text: "Ask too matter formed county wicket oppose talent",
            },
            trigger: {
              type: "reaction",
              text: "Eric reacted to your activity",
            },
          },
        },
      ],
    },
    {
      activity_count: 1,
      user_count: 1,
      group: "jane-follow-2025-08-04",
      activities: [
        {
          type: "follow",
          user: {
            id: "eric",
            name: "Eric",
          },
          notification_context: {
            target: {
              id: "jane",
              name: "Jane",
            },
            trigger: {
              type: "follow",
              text: "Eric started following you",
            },
          },
        },
      ],
    },
    {
      activity_count: 1,
      user_count: 1,
      group: "comment456-comment_reply-2025-08-04",
      activities: [
        {
          type: "comment_reply",
          user: {
            id: "charlie",
            name: "Charlie"
          },
          notification_context: {
            target: {
              id: "8966090a-30bf-4fe2-b8bc-b0fe36200e56",
              user_id: "alice",
              type: "post",
              text: "Ask too matter formed county wicket oppose talent",
              comment: {
                id: "comment456",
                user_id: "bob",
                comment: "Great post! I totally agree with this."
              }
            },
            trigger: {
              type: "comment_reply",
              text: "Charlie replied to your comment"
            }
          }
        }
      ]
    },
  ];
}
```

## Push Notifications

For information on configuring push notifications, see [Feed Group Push Configuration](/activity-feeds/docs/javascript/feed_group_push_configuration/).

## Notification status

If notification tracking is turned on for the feed group then you'll receive notification status when reading the feed. Notification status tells

- How many unread notifications does the feed have?
- Which notifications are read?
- How many unseen notifications does the feed have?
- Which notifications are seen?

Unread/unseen count is computed from the last 1000 activities of the feed, and aggregated into maximum 100 groups. This means that unread/unseen count will never be more than 100.

For example, take the notification system on Facebook. If you click the notification icon, all notifications get marked as seen. However, an individual notification only gets marked as read when you click on it.

Here is an example payload for notificaiton status:

<codetabs>

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

```js
{
  notification_status: {
    // Number of unread notifications
    unread: 12,
    // Number of unseen notifications
    unseen: 0,
    last_seen_at: // Date object with last seen timestamp,
    seen_activities: [],
    last_read_at: // Date object with last read timestamp,
    read_activities: ['activity123-reaction-2025-08-04'],
  }
}

// Check if a group is read/seen
const isRead = (lastReadAt && group.updated_at.getTime() < lastReadAt.getTime()) || readActivities.includes(group.group);
const isSeen = (lastSeenAt && group.updated_at.getTime() < lastSeenAt.getTime()) || seenActivities.includes(group.group);
```

</codetabs-item>

<codetabs-item value="react" label="React">

```js
{
  notification_status: {
    // Number of unread notifications
    unread: 12,
    // Number of unseen notifications
    unseen: 0,
    last_seen_at: // Date object with last seen timestamp,
    seen_activities: [],
    last_read_at: // Date object with last read timestamp,
    read_activities: ['activity123-reaction-2025-08-04'],
  }
}

 const {
  unread,
  unseen,
  last_read_at,
  last_seen_at,
  read_activities,
  seen_activities,
} = useNotificationStatus(feed) ?? {};

const isRead = useIsAggregatedActivityRead({ feed, aggregatedActivity });
const isSeen = useIsAggregatedActivitySeen({ feed, aggregatedActivity });
```

</codetabs-item>

<codetabs-item value="reactnative" label="React Native">

```js
{
  notification_status: {
    // Number of unread notifications
    unread: 12,
    // Number of unseen notifications
    unseen: 0,
    last_seen_at: // Date object with last seen timestamp,
    seen_activities: [],
    last_read_at: // Date object with last read timestamp,
    read_activities: ['activity123-reaction-2025-08-04'],
  }
}

const {
  unread,
  unseen,
  last_read_at,
  last_seen_at,
  read_activities,
  seen_activities,
} = useNotificationStatus(feed) ?? {};

const isRead = useIsAggregatedActivityRead({ feed, aggregatedActivity });
const isSeen = useIsAggregatedActivitySeen({ feed, aggregatedActivity });
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
{
  notification_status: {
    // Number of unread notifications
    unread: 12,
    // Number of unseen notifications
    unseen: 0,
    last_seen_at: // Date object with last seen timestamp,,
    seen_activities: [],
    last_read_at: // Date object with last read timestamp,,
    read_activities: ['activity-reaction-2025-08-04'],
  }
}

// Check if a group is read/seen
const isRead = (lastReadAt && group.updated_at.getTime() < lastReadAt.getTime()) || readActivities.includes(group.group);
const isSeen = (lastSeenAt && group.updated_at.getTime() < lastSeenAt.getTime()) || seenActivities.includes(group.group);
```

</codetabs-item>

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

```js
{
  NotificationStatus: {
    // Number of unread notifications
    Unread: 12,
    // Number of unseen notifications
    Unseen: 0,
    LastReadAt: // Timestamp object with last seen timestamp,,
    SeenActivities: [],
    LastSeenAt: // Timestamp object with last read timestamp,,
    ReadActivities: ['activity123-reaction-2025-08-04'],
  }
}

import (
	// Other imports...
	"slices"
)

// Check if a group is read/seen
group := response.Data.AggregatedActivities[0]
lastSeenAt := response.Data.NotificationStatus.LastSeenAt
seenActivities := response.Data.NotificationStatus.SeenActivities
lastReadAt := response.Data.NotificationStatus.LastReadAt
readActivities := response.Data.NotificationStatus.ReadActivities

isRead := (lastReadAt != nil && lastReadAt.Time != nil && group.UpdatedAt.Time != nil && group.UpdatedAt.Time.Before(*lastReadAt.Time)) || slices.Contains(readActivities, group.Group)

isSeen := (lastSeenAt != nil && lastSeenAt.Time != nil && group.UpdatedAt.Time != nil && group.UpdatedAt.Time.Before(*lastSeenAt.Time)) || slices.Contains(seenActivities, group.Group)
```

</codetabs-item>

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

```php
use GetStream\GeneratedModels;

{
  "notificationStatus": {
    // Number of unread notifications
    "unread": 12,
    // Number of unseen notifications
    "unseen": 0,
    "lastSeenAt": // DateTime object with last seen timestamp,
    "seenActivities": [],
    "lastReadAt": // DateTime object with last read timestamp,
    "readActivities": ["activity123-reaction-2025-08-04"],
  }
}

// Check if a group is read/seen
$group = $response->getData()->aggregatedActivities[0];
$lastSeenAt = $response->getData()->notificationStatus->lastSeenAt;
$seenActivities = $response->getData()->notificationStatus->seenActivities;
$lastReadAt = $response->getData()->notificationStatus->lastReadAt;
$readActivities = $response->getData()->notificationStatus->readActivities;

$isRead = ($lastReadAt && $group->updatedAt->getTimestamp() * 1e+9 < $lastReadAt->getTimestamp() * 1e+9) || ($readActivities && in_array($group->group, $readActivities));
$isSeen = ($lastSeenAt && $group->updatedAt->getTimestamp() * 1e+9 < $lastSeenAt->getTimestamp() * 1e+9) || ($seenActivities && in_array($group->group, $seenActivities));
```

</codetabs-item>

</codetabs>

## Marking notifications as seen

<codetabs>

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

```kotlin
notificationFeed.markActivity(
    request = MarkActivityRequest(
        // Mark all notifications as seen...
        markAllSeen = true,
        // ...or only selected ones
        markSeen = listOf(
            /* group names to mark as seen */
        )
    )
)
```

</codetabs-item>

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

```js
await notificationFeed.markActivity({
  // Mark all notifications as seen...
  mark_all_seen: true,
  // ...or only selected ones
  mark_seen: [
    /* group names to mark as seen */
  ],
});
```

</codetabs-item>

<codetabs-item value="react" label="React">

```js
await notificationFeed.markActivity({
  // Mark all notifications as seen...
  mark_all_seen: true,
  // ...or only selected ones
  mark_seen: [
    /* group names to mark as seen */
  ],
});
```

</codetabs-item>

<codetabs-item value="reactnative" label="React Native">

```js
await notificationFeed.markActivity({
  // Mark all notifications as seen...
  mark_all_seen: true,
  // ...or only selected ones
  mark_seen: [
    /* group names to mark as seen */
  ],
});
```

</codetabs-item>

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

```dart
await notificationFeed.markActivity(
  request: const MarkActivityRequest(
    // Mark all notifications as seen...
    markAllSeen: true,
    // ...or only selected ones
    markSeen: [
      /* group names to mark as seen */
    ],
  ),
);
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
await notificationFeed.markActivity({
  // Mark all notifications as seen...
  mark_all_seen: true,
  // ...or only selected ones
  mark_seen: [
    /* group names to mark as seen */
  ],
  user_id: "<user id>",
});
```

</codetabs-item>

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

```go
notificationFeed := client.Feeds().Feed("notification", "john")

_, err = notificationFeed.MarkActivity(context.Background(), &getstream.MarkActivityRequest{
  // Mark all notifications as seen...
  MarkAllSeen: getstream.PtrTo(true),
  // ...or only selected ones
  MarkSeen: []string{
    // group names to mark as seen
  },
  UserID:      getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error:", err)
}
```

</codetabs-item>

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

```php
use GetStream\GeneratedModels;

$notificationFeed = $feedsClient->feed("notification", "john");

$notificationFeed->markActivity(new GeneratedModels\MarkActivityRequest(
    // Mark all notifications as seen...
    markAllSeen: true,
    // ...or only selected ones
    markSeen: [
        // group names to mark as seen
    ],
    userID: "john"
));
```

</codetabs-item>

</codetabs>

## Marking notifications as read

<partial id="activity-feeds/v3-latest/_default/_partials/marking-notifications-as-read"></partial>

## Pagination

Pagination for notification (aggregated) feeds work the same way as it works for any other feed:

<partial id="activity-feeds/v3-latest/_default/_partials/feed-pagination"></partial>


---

This page was last updated at 2026-03-05T19:01:29.143Z.

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