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

Feeds

Creating a Feed

// Feed with no extra fields, of feed group "user"
const feed = client.feeds.feed("user", "jack");
await feed.getOrCreate();
// Subscribe to WebSocket events for state updates
await feed.getOrCreate({ watch: true });

// More options
const feed = client.feeds.feed("user", "jack");
await feed.getOrCreate({
  data: {
    description: "My personal feed",
    name: "jack",
    visibility: "public",
  },
});

Reading a Feed

Here is a basic example of how to read a feed:

const feed = client.feed(group: "user", id: "john")
await feed.getOrCreate({ watch: true });
const currentState = feed.state.getLatestValue();

const feedData = currentState.feed;
const activities = currentState.activities;
const members = currentState.members;

// Or subscribe to state changes
feed.state.subscribe((state) => {
  // Called everytime the state changes
  console.log(state);
});

// or if you care only part of the state
feed.state.subscribeWithSelector(
  (state) => ({
    activities: state.activities,
  }),
  (state, prevState) => {
    console.log(state.activities, prevState.activities);
  },
);

The response will contain the following data.

You have more options when reading a feed, let’s go over a few:

const feed = client.feeds.feed("user", "jack");
const response = await feed.getOrCreate({
  limit: 10,
  filter: {
    filter_tags: ["green"], // filter activities with filter tag green
  },
  external_ranking: {
    user_score: 0.8, // additional data used for ranking
  },
  follower_pagination: {
    limit: 10,
  },
  following_pagination: {
    limit: 10,
  },
  member_pagination: {
    limit: 10,
  },
  view: "myview", // overwrite the default ranking or aggregation logic for this feed. good for split testing
});

Feed Pagination

Here is how you can read the next page on the feed:

const feed = client.feeds.feed("user", "jack");

// First page
await feed.getOrCreate({
  limit: 10,
  user_id: "user_id",
});

// Second page
await feed.getNextPage();

console.log(feed.state.getLatestValue().activities);

Filtering Examples

Another common use case is filtering a feed. This is trickier than it seems. Keep in mind that for performance reasons feeds often have to be computed on write time. To allow for filtering we expose the following API.

const feed = client.feeds.feed("user", "123");
// Add a few activities
client.upsertActivities({
  activities: [
    {
      fids: [feed.fid],
      type: "post",
      text: "first",
      filter_tags: ["green", "blue"],
    },
    {
      fids: [feed.fid],
      type: "post",
      text: "second",
      filter_tags: ["yellow", "blue"],
    },
    {
      fids: [feed.fid],
      type: "post",
      text: "third",
      filter_tags: ["orange"],
    },
  ],
});

const response = await feed.getOrCreate({
  filter: {
    filter_tags: ["blue"],
  },
});

The filter syntax also supports $or and $and, so here’s an example that’s a little more complicated:

// Get all the activities where tags contain "green" and type is "post" or tag contains "orange" and type is "activity"
const response = await feed.getOrCreate({
  filter: {
    $or: [
      {
        $and: [{ filter_tags: ["green"] }, { type: "post" }],
      },
      {
        $and: [{ filter_tags: ["orange"] }, { type: "activity" }],
      },
    ],
  },
});

Feed Members

You can add and remove members to a feed. This is useful for building communities where a set of users can add content to the feed.

// The following methods are available to add or edit the members of a feed
await feed.updateFeedMembers({
  operation: "upsert",
  members: [
    {
      user_id: "john",
      role: "moderator",
      custom: {
        joined: "2024-01-01",
      },
    },
  ],
});

// Remove members
await feed.updateFeedMembers({
  operation: "remove",
  members: [
    {
      user_id: "john",
    },
    {
      user_id: "jane",
    },
  ],
});

// Set members (overwrites the list)
await feed.updateFeedMembers({
  operation: "set",
  members: [
    {
      user_id: "john",
      role: "moderator",
    },
  ],
});

Member invites

You can invite members with the invite flag, where invited users can accept or reject the membership.

await invitingFeed.updateFeedMembers({
  operation: "upsert",
  members: [
    {
      user_id: "john",
      role: "moderator",
      invite: true,
      custom: {
        reason: "community builder",
      },
    },
  ],
});

const feed = johnClient.feed(invitingFeed.group, invitingFeed.id);
// Then John can accept or reject
await feed.acceptFeedMemberInvite();

await feed.rejectFeedMemberInvite();

Query Feeds

Querying feeds allows you to do things like showing the list of communities you’ve joined.

Here’s an example of how to query feeds:

Querying My Feeds

const firstPage = await client.queryFeeds({
  filter: {
    created_by_id: "john",
  },
  limit: 10,
  sort: [{ field: "created_at", direction: -1 }],
});

const secondPage = await client.queryFeeds({
  filter: {
    created_by_id: "john",
  },
  limit: 10,
  sort: [{ field: "created_at", direction: -1 }],
  next: firstPage.next,
});

Querying Feeds Where I Am a Member

await client.queryFeeds({
  filter: {
    members: { $in: ["john"] },
  },
});

Querying feeds by name or description

await client.queryFeeds({
  filter: {
    visibility: { $eq: "public" },
    name: { $q: "Sports" },
  },
});

// search public feeds by description
await client.queryFeeds({
  filter: {
    // Shorthand for the $eq operator
    visibility: "public",
    description: { $autocomplete: "tech" },
  },
});

Querying feeds by creator name

// search public feeds created by users with 'Thompson' in their name
await client.queryFeeds({
  filter: {
    visibility: "public",
    "created_by.name": { $q: "Thompson" },
  },
});

Feeds Queryable Built-in Fields

nametypedescriptionsupported operationsexample
idstring or list of stringsThe ID of the feed$in, $eq{ id: { $in: [ 'abc', 'xyz' ] } }
group_idstring or list of stringsThe ID of the group this feed belongs to$in, $eq{ group_id: { $in: [ 'abc', 'xyz' ] } }
fidstring or list of stringsThe fully qualified feed ID (group_id:id)$in, $eq{ fid: { $in: [ 'abc', 'xyz' ] } }
visibilitystring or list of stringsThe visibility setting of the feed$in, $eq{ visibility: { $eq: 'public' } }
created_by_idstring or list of stringsThe ID of the user who created the feed$in, $eq{ created_by_id: { $in: [ 'abc', 'xyz' ] } }
created_by.namestringThe name of the user who created the feed$eq, $q, $autocomplete{ 'created_by.name': { $autocomplete: 'Frank' } }
namestringThe name of the feed$eq, $q, $autocomplete{ name: { $q: 'Sports' } }
descriptionstringThe description of the feed$eq, $q, $autocomplete{ description: { $autocomplete: 'tech' } }
member_countnumberThe number of members in this feed$eq, $ne, $gt, $lt, $gte, $lte{ member_count: { $gt: 100 } }
memberslist of stringsThe list of members in this feed$in{ members: { $in: [ 'bob', 'alice' ] } }
following_countnumberThe number of feeds this feed follows$eq, $ne, $gt, $lt, $gte, $lte{ following_count: { $gt: 100 } }
following_feedslist of stringsThe list of feeds this feed follows$in{ following_feeds: { $in: [ 'feed1', 'feed2' ] } }
follower_countnumberThe number of followers of this feed$eq, $ne, $gt, $lt, $gte, $lte{ follower_count: { $gt: 100 } }
created_atstring, RFC3339 timestampThe time the feed was created$eq, $gt, $lt, $gte, $lte{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }
updated_atstring, RFC3339 timestampThe time the feed was updated$eq, $gt, $lt, $gte, $lte{ updated_at: { $gte: '2023-12-04T09:30:20.45Z' } }

Feeds can be sorted by created_at, updated_at, member_count, follower_count, and following_count.

Be sure to reach out to support if you need additional query feed capabilities.

© Getstream.io, Inc. All Rights Reserved.