const following_view = await serverClient.feeds.createFeedView({
view_id: uuidv4(),
activity_selectors: [
{
type: "following",
},
],
ranking: { type: "time" },
});
const myFeedGroup = await serverClient.feeds.createFeedGroup({
feed_group_id: "myid",
default_view_id: following_view.feed_view.view_id,
activity_processors: [
{
type: "topic",
},
],
custom: {
description: "My custom feed group",
},
});
Intro & Defaults
Creating Feed Groups & Defaults
There are several feed groups setup by default.
Group | Description |
---|---|
user | A feed setup for the content a user creates. Typically you add activities here when someone writes a post |
timeline | The timeline feed is used when you’re following. So if user Charlie is following John, timeline:charlie would follow user:john |
foryou | A version of the timeline feed that adds popular content, and priorities popularity over recency |
notification | A notification feed. Think of the bell icon you see in most apps |
You can also create your own feed group. Here’s how to create a feed group using the API:
package main
import (
"context"
"log"
"fmt"
"time"
"github.com/GetStream/getstream-go/v3"
)
func main() {
client, err := getstream.NewClient("<your_api_key>", "<your_api_secret>")
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
feedsClient := client.Feeds()
// Create a following view for the feed group
followingViewID := fmt.Sprintf("following-view-%d", time.Now().Unix())
followingView, err := feedsClient.CreateFeedView(ctx, &getstream.CreateFeedViewRequest{
ViewId: &followingViewID,
ActivitySelectors: []getstream.ActivitySelector{
{
Type: getstream.PtrTo("following"),
},
},
Ranking: &getstream.Ranking{
Type: getstream.PtrTo("time"),
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("Following view created: %s", *followingView.Data.ViewId)
// Create custom feed group with the view
myFeedGroup, err := feedsClient.CreateFeedGroup(ctx, &getstream.CreateFeedGroupRequest{
FeedGroupId: getstream.PtrTo("myid"),
DefaultViewId: followingView.Data.ViewId,
ActivityProcessors: []getstream.ActivityProcessor{
{
Type: getstream.PtrTo("topic"),
},
},
Custom: map[string]interface{}{
"description": "My custom feed group",
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("Custom feed group created: %+v", myFeedGroup.Data)
// Create aggregation view for notifications
aggregationViewID := fmt.Sprintf("aggregation-view-%d", time.Now().Unix())
aggregationView, err := feedsClient.CreateFeedView(ctx, &getstream.CreateFeedViewRequest{
ViewId: &aggregationViewID,
Aggregation: &getstream.AggregationConfig{
Format: getstream.PtrTo("{{ type }}-{{ time.strftime(\"%Y-%m-%d\") }}"),
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("Aggregation view created: %s", *aggregationView.Data.ViewId)
// Create notification feed group
notificationFeedGroup, err := feedsClient.CreateFeedGroup(ctx, &getstream.CreateFeedGroupRequest{
FeedGroupId: getstream.PtrTo("mynotifications"),
DefaultViewId: aggregationView.Data.ViewId,
Notification: &getstream.NotificationConfig{
TrackRead: getstream.PtrTo(true),
TrackSeen: getstream.PtrTo(true),
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("Notification feed group created: %+v", notificationFeedGroup.Data)
}
Activity Ranking
When ranking activities you can specify a ranking formula.
const view = await serverClient.feeds.createFeedView({
view_id: uuidv4(),
ranking: { type: "time", score: "decay_linear(time) * popularity" },
activity_selectors: [
{
type: "following",
},
],
});
const response = await serverClient.feeds.createFeedGroup({
feed_group_id: "mytimeline",
default_view_id: view.feed_view.view_id,
});
For you Feeds
Many apps want to have a “for you” or personalized feed. There are a couple benefits to a personalized feed:
- Works well even if your users don’t spend much time setting up follows
- Can be a mechanism to discover new content or things to follow
Stream offers a few built-in methods to create a for you feed and gives you the API access to do more advanced customization if needed.
This next example is a bit more complicated. It uses an activity processor to add topic data to activities and ranks content you’re likely to engage with higher in the feed.
const view = await serverClient.feeds.createFeedView({
view_id: uuidv4(),
ranking: { type: 'expression', score: 'decay_linear(time) * popularity' },
// Activity selectors change which activities are included in the feed
// The default "following" selectors gets activities from the feeds you follow
// The "popular" activity selectors includes the popular activities
// And "interest" activities similar to activities you've engaged with in the past
// You can use multiple selectors in 1 feed
activity_selectors: [
{
type: 'popular',
},
{
type: 'following',
},
{
type: 'interest',
},
],
// Rank for a user based on interest score
// This calculates a score 0-1.0 of how well the activity matches the user's prior interest
ranking: {
type: "interest",
score: "decay_linear(time) * interest * decay_linear(popularity)"
},
});
const response = await serverClient.feeds.createFeedGroup({
feed_group_id: 'mytimeline',
default_view_id: view.feed_view.view_id,
// Run the activity processors to analyse topics for text & images
activity_processors: [
{type: 'image_topic'},
{type: 'text_topic'}
]
});
const forYouFeed = client.feeds.feed(group: "mytimeline", id: "thierry")
const response = await forYouFeed.getOrCreate({ user_id: 'thierry' })
package main
import (
"context"
"log"
"fmt"
"time"
"github.com/GetStream/getstream-go/v3"
)
func main() {
client, err := getstream.NewClient("<your_api_key>", "<your_api_secret>")
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
feedsClient := client.Feeds()
// Create interest-based "For You" feed view
forYouViewID := fmt.Sprintf("for-you-view-%d", time.Now().Unix())
view, err := feedsClient.CreateFeedView(ctx, &getstream.CreateFeedViewRequest{
ViewId: &forYouViewID,
// Activity selectors change which activities are included in the feed
// The default "following" selectors gets activities from the feeds you follow
// The "popular" activity selectors includes the popular activities
// And "interest" activities similar to activities you've engaged with in the past
// You can use multiple selectors in 1 feed
ActivitySelectors: []getstream.ActivitySelector{
{
Type: getstream.PtrTo("popular"),
},
{
Type: getstream.PtrTo("following"),
},
{
Type: getstream.PtrTo("interest"),
},
},
// Rank for a user based on interest score
// This calculates a score 0-1.0 of how well the activity matches the user's prior interest
Ranking: &getstream.Ranking{
Type: getstream.PtrTo("interest"),
Score: getstream.PtrTo("decay_linear(time) * interest * decay_linear(popularity)"),
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("For You view created: %s", *view.Data.ViewId)
// Create feed group with activity processors for topic analysis
response, err := feedsClient.CreateFeedGroup(ctx, &getstream.CreateFeedGroupRequest{
FeedGroupId: getstream.PtrTo("mytimeline"),
DefaultViewId: view.Data.ViewId,
// Run the activity processors to analyse topics for text & images
ActivityProcessors: []getstream.ActivityProcessor{
{
Type: getstream.PtrTo("image_topic"),
},
{
Type: getstream.PtrTo("text_topic"),
},
},
Custom: map[string]interface{}{
"description": "Interest-based For You feed with topic analysis",
},
})
if err != nil {
log.Fatal(err)
}
log.Printf("For You feed group created: %+v", response.Data)
// Read the personalized "For You" feed
// Activities will include following, popular and similar (via interest) activities
// Sorted by time decay, interest and popularity
forYouFeed := feedsClient.Feed("mytimeline", "thierry")
feedResponse, err := forYouFeed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("thierry"),
})
if err != nil {
log.Fatal(err)
}
log.Printf("For You feed loaded with %d activities", len(feedResponse.Data.Activities))
log.Println("Activities include following, popular and interest-based content")
}
Aggregation & Notification Feeds
Aggregation groups similar activities together, which is useful for notification feeds and reducing noise.
Aggregation Format
You can create your own aggregated feeds:
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,
},
});
Notification Feed Example
The built-in notification
feed comes with the necessary configurations:
let notificationFeed = client.feed(group: "notification", id: "jane")
let notifications = try await notificationFeed.getOrCreate()
const notificationFeed = client.feed(group: "notification", id: "jane")
// Read notifications
const notifications = (await notificationFeed.getOrCreate({
limit: 20,
})).aggregated_activities;
const notificationFeed = client.feed(group: "notification", id: "jane")
// Read notifications
const notifications = (await notificationFeed.getOrCreate({
limit: 20,
user_id: '<user_id>'
})).aggregated_activities;
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 */
],
});
await notificationFeed.markActivity({
// Mark all notifications as read...
mark_all_read: true,
// ...or only selected ones
mark_read: [
/* group names to mark as read */
],
user_id: "<user id>",
});
Updating feed groups
It’s possible to update any custom or built-in feed group or view
await serverClient.feeds.updateFeedView({
view_id: "<view id to update?",
// Fields to update
});
await client.feeds.updateFeedGroup({
feed_group_id: "<id of feed group to update>",
// Fields to update
});
Deleting feed groups
await serverClient.feeds.deleteFeedView({
view_id: "view id to delete",
});
await serverClient.feeds.deleteFeedGroup({
feed_group_id: "<feed group id to delete>",
});
- I'm working with the Stream Feeds React Native SDK and would like to ask questions about this documentation page: https://getstream.io/activity-feeds/docs/react-native/feed-groups.md
- View as markdown
- Open in ChatGPT
- Open in Claude