# For You Feed

It's now common for apps to default to a "For you" style feed instead of just a following feed.
This section of the docs will explain how to build a for you feed with Stream.

While the exact logic differs per app, fundamently the "for you" feed does a 2 different things:

### 1 - Activity Selectors

The feed pulls in activities from different sources (activity selectors). Examples include:

- Popular activities
- Activities close to you
- Activities from people you follow
- Activities from your follow recommendations
- Specific editorial feeds
- Activities that match your interests
- Other activity queries/selections

Read more about the supported activity selectors in the ["Activity Selectors" guide](/activity-feeds/docs/go-golang/activity-selectors/)

### 2 - Ranking

After the feed combines the activities from different selectors it applies ranking.
Stream supports expression based ranking out of the box. This allows you to define a formula to rank activities.

In the example below we'll build a simple interest based for you feed, to read more about ranking, visit the ["Custom ranking" guide](/activity-feeds/docs/go-golang/custom-ranking/)

### Step 1 - Create a feed group

For the feed group we're enabling interest based ranking. We are ranking on `interest_score * popularity * decay_exp(time)`
For activity selectors we're also keeping it simple, showing just the activities from people you follow & popular activities.

You can also use `preference_score` in your ranking expression to incorporate user preferences based on activity feedback (show more/less). This allows the feed to prioritize content that users have explicitly indicated they want to see more of. See [Activity feedback](/activity-feeds/docs/go-golang/activity-feedback/) for more information.

We're also enabling [activity processors](/activity-feeds/docs/go-golang/activity-processors/).
The text topics activity processor uses an LLM to summarize the topics for an activity.
It writes this data to activity.interest_tags. This update happens in the background.

<Tabs>

```js label="Node"
const response = await serverClient.feeds.updateFeedGroup({
  id: "timeline",
  activity_selectors: [{ type: "following" }, { type: "popular" }],
  ranking: {
    type: "interest",
    score:
      "interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)",
  },
  activity_processors: [{ type: "text_interest_tags" }],
});
```

```go label="Go"
response, err := client.Feeds().UpdateFeedGroup(context.Background(), "timeline", &getstream.UpdateFeedGroupRequest{
    ActivitySelectors: []getstream.ActivitySelectorConfig{
        {Type: getstream.PtrTo("following")},
        {Type: getstream.PtrTo("popular")},
    },
    Ranking: &getstream.RankingConfig{
        Type:   getstream.PtrTo("interest"),
        Score:  getstream.PtrTo("interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)"),
    },
    ActivityProcessors: []getstream.ActivityProcessorConfig{
        {Type: "text_interest_tags"},
    },
})
if err != nil {
    log.Fatal("Error updating feed group:", err)
}
```

```php label="php"
$updateResponse = $feedsClient->updateFeedGroup('timeline', new GeneratedModels\UpdateFeedGroupRequest(
    activitySelectors: [
        new GeneratedModels\ActivitySelectorConfig(type: 'following'),
        new GeneratedModels\ActivitySelectorConfig(type: 'popular')
    ],
    ranking: new GeneratedModels\RankingConfig(
        type: 'interest',
        score: 'interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)',
    ),
    activityProcessors: [
        new GeneratedModels\ActivityProcessorConfig(type: 'text_interest_tags')
    ]
));
```

```csharp label="C#"
var updateResponse = await _feedsV3Client.UpdateFeedGroupAsync("feed_group_id", new UpdateFeedGroupRequest
{
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    },
    Aggregation = new AggregationConfig
    {
        Format = "time_based"
    }
});
```

```python label="Python"
update_response = self.client.feeds.update_feed_group(
    id="timeline",
    activity_selectors=[
        {"type": "following"},
        {"type": "popular"}
    ],
    ranking={
        "type": "interest",
        "score": "interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)"
    },
    activity_processors=[
        {"type": "text_interest_tags"}
    ]
)
```

```java label="Java"
import io.getstream.services.FeedsImpl;
import io.getstream.models.*;

FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

UpdateFeedGroupRequest request = UpdateFeedGroupRequest.builder()
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build(),
        ActivitySelectorConfig.builder().type("popular").build()
    ))
    .ranking(RankingConfig.builder()
        .type("interest")
        .score("interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)")
        .build())
    .activityProcessors(List.of(
        ActivityProcessorConfig.builder().type("text_interest_tags").build()
    ))
    .build();

UpdateFeedGroupResponse response = feedsClient.updateFeedGroup("timeline", request).execute().getData();
```

```csharp label="C#"
var updateResponse = await _feedsV3Client.UpdateFeedGroupAsync("timeline", new UpdateFeedGroupRequest
{
    ActivitySelectors = new List<ActivitySelectorConfig>
    {
        new() { Type = "following" },
        new() { Type = "popular" }
    },
    Ranking = new RankingConfig
    {
        Type = "interest",
        Score = "interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)"
    },
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "text_interest_tags" }
    }
});
```

</Tabs>

<admonition type="tip">

**Using preference_score**: To incorporate user feedback into your ranking, you can use `preference_score` in your ranking expression. For example, to combine both interest-based and preference-based ranking:

```js
score: "preference_score * interest_score * (popularity > 0 ? popularity : 1) * decay_exp(time)";
```

This will boost activities that match both the user's interests and their explicit preferences from activity feedback.

</admonition>

## Step 2 - Activities with interest tags

Let's add 2 activities to a feed

<Tabs>

```js label="Node"
const feed = client.feeds.feed("user", "jack");

// since we've enabled the "text_topics" activity processor the "activity.interest_tags" will be automatically set
const response = await client.feeds.addActivity({
  feeds: [feed.feed]
  type: "post",
  text: "apple stock will go up",
  user_id: 'jack'
});

// you can also set this field manually
const response = await client.feeds.addActivity({
  feeds: ["user:1", "stock:apple"],
  type: "post",
  text: "apple stock will go up",
  interest_tags: ["apple", "stock"],
  user_id: 'jack'
});
```

```go label="Go"
response, err := client.Feeds().AddActivity(context.Background(), &getstream.AddActivityRequest{
    Feeds:  []string{"user:john"},
    Type:   "post",
    Text:   getstream.PtrTo("apple stock will go up"),
    UserID: getstream.PtrTo("john"),
})
if err != nil {
    log.Fatal("Error adding activity:", err)
}

// you can also set this field manually
response2, err := client.Feeds().AddActivity(context.Background(), &getstream.AddActivityRequest{
    Feeds:        []string{"user:john"},
    Type:         "post",
    Text:         getstream.PtrTo("apple stock will go up"),
    InterestTags: []string{"apple", "stock"},
    UserID:       getstream.PtrTo("john"),
})
if err != nil {
    log.Fatal("Error adding activity with manual interest tags:", err)
}
```

```java label="Java"
AddActivityRequest activity =
    AddActivityRequest.builder()
        .type("post")
        .feeds(List.of(testFeedId))
        .text("This is a test activity from Java SDK")
        .userID(testUserId)
        .build();

AddActivityResponse response = feeds.addActivity(activity).execute().getData();
```

```php label="php"
// since we've enabled the "text_interest_tags" activity processor the "interest_tags" will be automatically set
$response = $feedsClient->addActivity(new GeneratedModels\AddActivityRequest(
    type: 'post',
    feeds: ['user:jack'],
    text: 'apple stock will go up',
    userID: 'jack'
));

// you can also set this field manually
$response = $feedsClient->addActivity(new GeneratedModels\AddActivityRequest(
    type: 'post',
    feeds: ['user:1', 'stock:apple'],
    text: 'apple stock will go up',
    interestTags: ['apple', 'stock'],
    userID: 'jack'
));
```

```csharp label="C#"
var activity = new AddActivityRequest
{
    Type = "post",
    Text = "This is a test activity from .NET SDK",
    UserID = _testUserId,
    Feeds = new List<string> { $"user:{_testFeedId}" }
};
var response = await _feedsV3Client.AddActivityAsync(activity);
```

```python label="Python"
response = self.client.feeds.add_activity(
    type="post",
    feeds=[self.test_feed.get_feed_identifier()],
    text="This is a test activity from Python SDK",
    user_id=self.test_user_id,
    custom={
        "test_field": "test_value",
        "timestamp": int(datetime.now().timestamp()),
    },
)
```

</Tabs>

The important part here is that the activity has the interest tags set.

## Step 3 - Reading the interest based ranked feed

When reading an interest based feed you can either have Stream automatically calculate the interest weights, or pass them manually.

<Tabs>

```js label="Node"
const interestWeights = {
  go: 1.0, // User loves Go
  python: 0.5, // User is ok with Python
  ruby: -1.0, // User dislikes Ruby
};
const feed = client.feeds.feed("user", "jack");
const response = await feed.getOrCreate({
  limit: 10,
  interest_weights: interestWeights, // Optionally overwrite the default interest weights for this feed
  user_id: "jack",
});
```

```go label="Go"
// Define interest weights
interestWeights := map[string]float64{
    "go":     1.0,  // User loves Go
    "python": 0.5,  // User is ok with Python
    "ruby":   -1.0, // User dislikes Ruby
}

// Get feed instance
feed := client.Feeds().Feed("user", "john")

// Call getOrCreate with interest weights
response, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
    Limit:           getstream.PtrTo(10),
    InterestWeights: interestWeights, // Optionally overwrite the default interest weights for this feed
    UserID:          getstream.PtrTo("john"),
})
if err != nil {
    log.Fatal("Error calling GetOrCreate:", err)
}
```

```java label="Java"
testFeed = new Feed("user", testUserId, feeds);
testFeed2 = new Feed("user", testUserId2, feeds);

GetOrCreateFeedRequest feedRequest1 =
    GetOrCreateFeedRequest.builder().userID(testUserId).build();
GetOrCreateFeedRequest feedRequest2 =
    GetOrCreateFeedRequest.builder().userID(testUserId2).build();

GetOrCreateFeedResponse feedResponse1 = testFeed.getOrCreate(feedRequest1).getData();
GetOrCreateFeedResponse feedResponse2 = testFeed2.getOrCreate(feedRequest2).getData();
testFeedId = feedResponse1.getFeed().getFeed();
testFeedId2 = feedResponse2.getFeed().getFeed();
```

```php label="php"
$interestWeights = [
    'go' => 1.0,      // User loves Go
    'python' => 0.5,  // User is ok with Python
    'ruby' => -1.0,   // User dislikes Ruby
];

$response = $feedsClient->getOrCreateFeed('user', 'jack', new GeneratedModels\GetOrCreateFeedRequest(
    limit: 10,
    interestWeights: $interestWeights, // Optionally overwrite the default interest weights for this feed
    userID: 'jack'
));
```

```csharp label="C#"
var feedResponse1 = await _feedsV3Client.GetOrCreateFeedAsync(
    FeedGroupID: "user",
    FeedID: _testFeedId,
    request: new GetOrCreateFeedRequest { UserID = _testUserId }
);
var feedResponse2 = await _feedsV3Client.GetOrCreateFeedAsync(
    FeedGroupID: "user",
    FeedID: _testFeedId2,
    request: new GetOrCreateFeedRequest { UserID = _testUserId2 }
);
```

```python label="Python"
feed_response_1 = self.test_feed.get_or_create(user_id=self.test_user_id)
feed_response_2 = self.test_feed_2.get_or_create(
    user_id=self.test_user_id_2
)
```

</Tabs>

<admonition type="info">

**Following from For You Feed**: When a user follows someone or content from the forYouFeed, this does not automatically add them to the user's timeline feed. If you want these follows to appear in the timeline feed, you need to explicitly create a follow connection between the timeline feed and the target feed when handling the follow action.

</admonition>

### Conclusion

In a few lines of code you created an interest based "for you" style feed. It includes popular content as well as activities from the people you follow.
Activities from topics you engage with are shown higher in the feed.

This example kept things pretty basic but you can make it more complex.

- You could include activities based on their interest_tags. So if someone engages with content about snowboarding you could show them more of that
- Images can also be processed for interest tags
- More ranking & activity selectors can be added. Activities close to you, activities from follow suggestions etc.

You can build infinitely complex "for you" style feeds with ranking & activity selectors.
Be sure to reach out to our support team in case anything is missing.
We're often adding selector or processors based on customer feedback.


---

This page was last updated at 2026-05-22T16:31:48.532Z.

For the most recent version of this documentation, visit [https://getstream.io/activity-feeds/docs/go-golang/for-you-feed/](https://getstream.io/activity-feeds/docs/go-golang/for-you-feed/).