Activity Feeds V3 is in closed alpha — do not use it in production (just yet).

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:

const aggregation_view = await serverClient.feeds.createFeedView({
  view_id: uuidv4(),
  // Group by activity type and day
  aggregation: { format: '{{ type }}-{{ time.strftime("%Y-%m-%d") }}' },
});

const myNotificationGrpup = await serverClient.feeds.createFeedGroup({
  feed_group_id: "myid",
  default_view_id: aggregation_view.feed_view.view_id,
  // Enable notification tracking
  notification: {
    track_read: true,
    track_seen: true,
  },
});

Aggregation format

The built-in notification feed uses the following aggregation format: "{{ 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.

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).

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.

Built-in notification feed

Creating notification activities

The built-in notification feed allows you to automatically create notification activities.

// 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({
  comment_id: saraComment.id,
  type: "like",
  // When true Sara's notification feed will be updated with comment reaction activity
  create_notification_activity: true,
});

Reading notification activities

const notificationFeed = client.feed(group: "notification", id: "jane")

// Read notifications
const notifications = (await notificationFeed.getOrCreate({
    limit: 20,
})).aggregated_activities;

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

  • Three aggregated activity groups:
    • comment-2025-08-04
    • reaction-2025-08-04
    • 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
{
  aggregated_activities: [
    {
      activity_count: 1,
      user_count: 1,
      group: "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",
            },
          },
          // Other activity fields
        },
      ],
    },
    {
      activity_count: 1,
      user_count: 1,
      group: "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: "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",
            },
          },
        },
      ],
    },
  ];
}

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?

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:

{
  notification_status: {
    // Number of unread notifications
    unread: 12,
    // Number of unseen notifications
    unseen: 0,
    last_seen_at: 1754309822808392000,
    seen_activities: [],
    last_read_at: 1754309822808392000,
    read_activities: ['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);

Marking notifications as seen

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

Marking notifications as read

await notificationFeed.markActivity({
  // Mark all notifications as read...
  mark_all_read: true,
  // ...or only selected ones
  mark_read: [
    /* group names to mark as read */
  ],
});
© Getstream.io, Inc. All Rights Reserved.