Event Handling

Overview

Stream Feeds provides real-time event handling, allowing you to react to various changes in the feed system.

Available Events

Event Name Description
Activity Events
feeds.activity.added Fired when a new activity is added to a feed
feeds.activity.updated Fired when an activity is modified
feeds.activity.deleted Fired when an activity is removed
feeds.activity.restored Fired when an activity is restored
feeds.activity.removed_from_feed Fired when an activity is removed from a specific feed
feeds.activity.pinned Fired when an activity is pinned to the top
feeds.activity.unpinned Fired when an activity is unpinned
feeds.activity.feedback Fired when activity feedback is provided
feeds.activity.marked Fired when an activity is marked
Notification Events
feeds.notification_feed.updated Fired when the notification status, or notification groups (aggregated activities) are updated
Comment Events
feeds.comment.added Fired when a new comment is added to an activity
feeds.comment.updated Fired when a comment is modified
feeds.comment.deleted Fired when a comment is removed
feeds.comment.restored Fired when a comment is restored
Reaction Events
feeds.activity.reaction.added Fired when a reaction is added to an activity
feeds.activity.reaction.deleted Fired when a reaction is removed from an activity
feeds.activity.reaction.updated Fired when a reaction on an activity is updated
feeds.comment.reaction.added Fired when a reaction is added to a comment
feeds.comment.reaction.deleted Fired when a reaction is removed from a comment
feeds.comment.reaction.updated Fired when a reaction on a comment is updated
Poll Events
feeds.poll.closed Fired when a poll is closed
feeds.poll.deleted Fired when a poll is deleted
feeds.poll.updated Fired when a poll is modified
feeds.poll.vote_casted Fired when a vote is cast
feeds.poll.vote_changed Fired when a vote is changed
feeds.poll.vote_removed Fired when a vote is removed
Feed Events
feeds.feed.created Fired when a new feed is created
feeds.feed.updated Fired when a feed is modified
feeds.feed.deleted Fired when a feed is deleted
Feed Group Events
feeds.feed_group.changed Fired when a feed group is changed
feeds.feed_group.deleted Fired when a feed group is deleted
feeds.feed_group.restored Fired when a feed group is restored
Member Events
feeds.feed_member.added Fired when a member is added to a feed
feeds.feed_member.removed Fired when a member is removed from a feed
feeds.feed_member.updated Fired when a member's role/permissions change
Follow Events
feeds.follow.created Fired when a follow relationship is created
feeds.follow.deleted Fired when a follow relationship is removed
feeds.follow.updated Fired when follow settings are modified
Bookmark Events
feeds.bookmark.added Fired when an activity is bookmarked
feeds.bookmark.deleted Fired when a bookmark is removed
feeds.bookmark.updated Fired when bookmark metadata is modified
feeds.bookmark_folder.deleted Fired when bookmark folder is deleted
feeds.bookmark_folder.updated Fired when bookmark folder is updated
Stories Events
feeds.stories_feed.updated Fired when a stories feed is updated
Moderation Events
moderation.custom_action Fired when a custom moderation action is performed
moderation.flagged Fired when content is flagged for moderation
moderation.mark_reviewed Fired when content is marked as reviewed
App Events
app.updated Fired when the app configuration changes
Connection Events
health.check The periodic keep-alive on the WebSocket connection
connection.ok Fired when the WebSocket connection is established
connection.error Fired when the WebSocket connection fails
User Events
user.banned Fired when a user is banned
user.deactivated Fired when a user is deactivated
user.reactivated Fired when a user is reactivated
user.unbanned Fired when a user is unbanned
user.updated Fired when a user is updated

Listening to events

client.events emits every WebSocket event the client receives.

// Listen to all WebSocket events from the client
client.events.listen((event) {
  print('Received event: ${event.runtimeType}');
});
Note:

You rarely need to pattern-match on the event classes: the SDK applies each event to the state of the feeds, activities and lists you hold, so following that state is the idiomatic way to react to a change.

Following a feed's state

Real-time updates require a watched feed. FeedQuery.watch defaults to true, so a feed you create the plain way is already watched.

// Real-time updates require a watched feed. `watch` defaults to true, so a
// plain `client.feed(...)` is already watched; pass false to opt out.
final feed = client.feedFromQuery(
  const FeedQuery(fid: FeedId.user('john'), watch: true),
);
await feed.getOrCreate();

// The SDK applies each event to the feed's state, so following the state is
// usually all an app needs.
feed.stream.listen((state) {
  print('${state.activities.length} activities');
});

Feed.stream emits the whole FeedState after each change. See State Layer for what it holds.

Warning:

A watched query is rejected when the client connected with connectWebSocket: false. See Connecting without a WebSocket.

Notification feed state

For a notification feed, the state carries the unread and unseen counts and the per-group read state, all of which stay current as events arrive.

// The feed state stream emits whenever the feed state changes (activities,
// aggregated groups, notification status, etc.)
notificationFeed.stream.listen((state) {
  final unread = state.notificationStatus?.unread ?? 0;
  final unseen = state.notificationStatus?.unseen ?? 0;
  print('Unread: $unread, Unseen: $unseen');

  // Per-activity isRead/isSeen are updated automatically when the
  // activity.marked WebSocket event arrives after markActivity() calls.
  for (final group in state.aggregatedActivities) {
    print('Group ${group.group}: read=${group.isRead}, seen=${group.isSeen}');
  }
});

markActivity produces a feeds.activity.marked event, and the SDK uses it to update the isRead and isSeen flags on the feed's state. That is also how a mark performed on another device shows up here.

// The activity.marked WS event fires when activities are marked read/seen.
// The SDK automatically updates the feed state's isRead/isSeen flags.
// Observe changes via the feed state stream:
notificationFeed.stream.listen((state) {
  final unreadCount = state.notificationStatus?.unread ?? 0;
  print('Unread count updated: $unreadCount');

  // All aggregated groups with their current read state
  final unreadGroups = state.aggregatedActivities.where((g) => g.isRead != true);
  print('Unread groups: ${unreadGroups.length}');
});

Connection events

// The connection's own comings and goings
client.connectionState.listen((state) {
  print('Connection state: $state');
});

A disconnection carries the source that closed it and whether it is worth reopening. See Error Handling.

Server-side webhooks

Webhooks are configured with your API secret, so they belong on your backend rather than in the app you ship. Setting up an endpoint, verifying signatures, retries and event failover are covered under Event handling in the server-side docs, with the full transport reference in the platform webhooks guide.