# Intro & Defaults

Feed groups are templates that define how different feeds behave in your application. The configuration options let you create feeds that work differently depending on your use case.

By adjusting settings like ranking, aggregation, activity selectors, and processors, you can tailor each feed group to serve specific purposes in your app.

<admonition type="info">

Note that any write operation to feed groups/views can take up to 30 seconds to propagate to all API nodes.

</admonition>


## Built-in groups

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 prioritizes popularity over recency                              |
| `notification` | A notification feed. Think of the bell icon you see in most apps                                                               |
| `story`        | A feed set up for users to post story activities (activities with expiration data)                                             |
| `stories`      | A timeline feed which can be used to follow other users' stories.                                                              |


You can update the default feed group configurations or create your own feed groups.

## Create feed groups

Here's how to create a feed group using the API:

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
const myFeedGroup = await serverClient.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "following",
    },
  ],
  ranking: { type: "recency" },
  activity_processors: [
    {
      type: "text_interest_tags",
    },
  ],
  custom: {
    description: "My custom feed group",
  },
});
```

</codetabs-item>

<codetabs-item value="go-golang" label="Go">

```go
ctx := context.Background()

myFeedGroup, err := client.Feeds().CreateFeedGroup(ctx, &getstream.CreateFeedGroupRequest{
    ID: "myid",
    ActivitySelectors: []getstream.ActivitySelectorConfig{
        {
            Type: getstream.PtrTo("following"),
        },
    },
    Ranking: &getstream.RankingConfig{
        Type: getstream.PtrTo("recency"),
    },
    ActivityProcessors: []getstream.ActivityProcessorConfig{
        {
            Type: "text_interest_tags",
        },
    },
    Custom: map[string]any{
        "description": "My custom feed group",
    },
})
if err != nil {
    log.Fatal("Error creating feed group:", err)
}

fmt.Printf("Feed group created successfully: %+v\n", myFeedGroup.Data.FeedGroup)
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
use GetStream\GeneratedModels\CreateFeedGroupRequest;
use GetStream\GeneratedModels\ActivitySelectorConfig;
use GetStream\GeneratedModels\RankingConfig;
use GetStream\GeneratedModels\ActivityProcessorConfig;

// Create feed group request
$request = new CreateFeedGroupRequest(
    id: "myid",
    activitySelectors: [
        new ActivitySelectorConfig(type: "following")
    ],
    ranking: new RankingConfig(type: "recency"),
    activityProcessors: [
        new ActivityProcessorConfig(type: "text_interest_tags")
    ],
    custom: (object) [
        "description" => "My custom feed group"
    ]
);

// Create the feed group
$response = $feedsClient->createFeedGroup($request);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

# Assuming you have an initialized API client
# client = GetStream::Client.new(api_key: ENV['STREAM_KEY'], api_secret: ENV['STREAM_SECRET'])

request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: "myid",
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(type: "following")
  ],
  ranking: GetStream::Generated::Models::RankingConfig.new(type: "recency"),
  activity_processors: [
    GetStream::Generated::Models::ActivityProcessorConfig.new(type: "text_interest_tags")
  ],
  custom: { description: "My custom feed group" }
)

response = client.feeds.create_feed_group(request)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
import io.getstream.services.FeedsImpl;
import io.getstream.models.*;

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

CreateFeedGroupRequest request = CreateFeedGroupRequest.builder()
    .id("myid")
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build()
    ))
    .ranking(RankingConfig.builder().type("recency").build())
    .activityProcessors(List.of(
        ActivityProcessorConfig.builder().type("text_interest_tags").build()
    ))
    .custom(Map.of("description", "My custom feed group"))
    .build();

CreateFeedGroupResponse response = feedsClient.createFeedGroup(request).execute().getData();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var request = new CreateFeedGroupRequest
{
    ID = "myid",
    ActivitySelectors = new List<ActivitySelectorConfig>
    {
        new() { Type = "following" }
    },
    Ranking = new RankingConfig
    {
        Type = "recency"
    },
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "text_interest_tags" }
    },
    Custom = new Dictionary<string, object>
    {
        ["description"] = "My custom feed group"
    }
};

var response = await _feedsV3Client.CreateFeedGroupAsync(request);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
request = {
    "id": "myid",
    "activity_selectors": [
        {"type": "following"}
    ],
    "ranking": {
        "type": "recency"
    },
    "activity_processors": [
        {"type": "text_interest_tags"}
    ],
    "custom": {
        "description": "My custom feed group"
    }
}

response = self.client.feeds.create_feed_group(**request)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
import io.getstream.services.FeedsImpl;
import io.getstream.models.*;

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

CreateFeedGroupRequest request = CreateFeedGroupRequest.builder()
    .id("myid")
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build()
    ))
    .ranking(RankingConfig.builder().type("recency").build())
    .activityProcessors(List.of(
        ActivityProcessorConfig.builder().type("text_interest_tags").build()
    ))
    .custom(Map.of("description", "My custom feed group"))
    .build();

CreateFeedGroupResponse response = feedsClient.createFeedGroup(request).execute().getData();
```

</codetabs-item>

</codetabs>

<admonition type="info">

Applications can't have more than 100 feed groups

</admonition>

### Overview of the feed group model

<open-api-models modelname="FeedGroupResponse" recursive="false" headerlevel="4">
</open-api-models>

Alternatively you can use the `getOrCreateFeedGroup` endpoint that will create and apply settings, or return the existing group.

## List feed groups

To list existing feed groups and their configurations:

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
await client.feeds.listFeedGroups();
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
// List all feed groups (excluding soft-deleted ones)
$response = $feedsClient->listFeedGroups(false);

// List all feed groups including soft-deleted ones
$response = $feedsClient->listFeedGroups(true);
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
response, err := client.Feeds().ListFeedGroups(context.Background(), &getstream.ListFeedGroupsRequest{})
if err != nil {
    log.Fatal("Error listing feed groups:", err)
}
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
import io.getstream.services.FeedsImpl;

FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));
ListFeedGroupsResponse response = feedsClient.listFeedGroups(false).execute().getData();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var response = await _feedsV3Client.ListFeedGroupsAsync(false);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# List all feed groups (excluding soft-deleted ones)
response = self.client.feeds.list_feed_groups(include_deleted=False)

# List all feed groups including soft-deleted ones
response = self.client.feeds.list_feed_groups(include_deleted=True)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# List all feed groups (excluding soft-deleted ones)
response = client.feeds.list_feed_groups(false)

# List all feed groups including soft-deleted ones
response = client.feeds.list_feed_groups(true)
```

</codetabs-item>

</codetabs>

## Activity Ranking

When ranking activities you can specify a ranking formula.

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
const response = await serverClient.feeds.createFeedGroup({
  id: "mytimeline",
  ranking: { type: "expression", score: "decay_linear(time) * popularity" },
  activity_selectors: [
    {
      type: "following",
    },
  ],
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
ctx := context.Background()

createFeedGroupRequest := &getstream.CreateFeedGroupRequest{
    ID: "mytimeline",
    Ranking: &getstream.RankingConfig{
        Type:  getstream.PtrTo("expression"),
        Score: getstream.PtrTo("decay_linear(time) * popularity"),
    },
    ActivitySelectors: []getstream.ActivitySelectorConfig{
        {
            Type: getstream.PtrTo("following"),
        },
    },
}

// Create the feed group
response, err := client.Feeds().CreateFeedGroup(ctx, createFeedGroupRequest)
if err != nil {
    log.Fatal("Error creating feed group:", err)
}

fmt.Printf("Feed group created successfully!\n")
fmt.Printf("Duration: %s\n", response.Data.Duration)
fmt.Printf("Feed Group ID: %s\n", response.Data.FeedGroup.ID)
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "mytimeline",
        defaultVisibility: 'public',
        ranking: new GeneratedModels\RankingConfig(
            type: 'expression',
            score: 'decay_linear(time) * popularity'
        ),
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: 'following'
            )
        ]
    )
);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = "ranked-group",
    DefaultVisibility = "public",
    Ranking = new RankingConfig
    {
        Type = "default",
        Score = "decay_linear(time) * popularity"
    }
});
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
    ranking=RankingConfig(
        type="default",
        score="decay_linear(time) * popularity"
    )
)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

response = client.feeds.create_feed_group(
  GetStream::Generated::Models::CreateFeedGroupRequest.new(
    id: 'mytimeline',
    ranking: GetStream::Generated::Models::RankingConfig.new(
      type: 'expression',
      score: 'decay_linear(time) * popularity'
    ),
    activity_selectors: [
      GetStream::Generated::Models::ActivitySelectorConfig.new(type: 'following')
    ]
  )
)
```

</codetabs-item>

</codetabs>


## 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](/activity-feeds/docs/react/activity_processors/) to add topic data to activities, [activity selectors](/activity-feeds/docs/react/activity_selectors/) to pull in content from different sources, and ranks content you're likely to engage with higher in the feed.

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
const response = await serverClient.feeds.createFeedGroup({
  id: "mytimeline",
  // Run the activity processors to analyse topics for text & images
  activity_processors: [
    { type: "text_interest_tags" },
    { type: "image_interest_tags" },
  ],
  // 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_score * decay_linear(popularity)",
  },
});

const forYouFeed = client.feeds.feed("mytimeline", "thierry");
const response = await forYouFeed.getOrCreate({ user_id: "thierry" });
```

</codetabs-item>

<codetabs-item value="go-golang" label="Go">

```go
ctx := context.Background()

// Create feed group with activity processors, activity selectors, and ranking
createFeedGroupRequest := &getstream.CreateFeedGroupRequest{
    ID: "mytimeline",
    // Run the activity processors to analyse topics for text & images
    ActivityProcessors: []getstream.ActivityProcessorConfig{
        {Type: "text_interest_tags"},
        {Type: "image_interest_tags"},
    },
    // 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.ActivitySelectorConfig{
        {
            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.RankingConfig{
        Type:  getstream.PtrTo("interest"),
        Score: getstream.PtrTo("decay_linear(time) * interest_score * decay_linear(popularity)"),
    },
}

// Create the feed group
response, err := client.Feeds().CreateFeedGroup(ctx, createFeedGroupRequest)
if err != nil {
    log.Fatal("Error creating feed group:", err)
}

fmt.Printf("Feed group created successfully!\n")
fmt.Printf("Duration: %s\n", response.Data.Duration)
fmt.Printf("Feed Group ID: %s\n", response.Data.FeedGroup.ID)

// Create and get the feed for a specific user
forYouFeed := client.Feeds().Feed("mytimeline", "thierry")
feedResponse, err := forYouFeed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
    UserID: getstream.PtrTo("thierry"),
})
if err != nil {
    log.Fatal("Error getting or creating feed:", err)
}

fmt.Printf("Feed created/retrieved successfully!\n")
fmt.Printf("Feed ID: %s\n", feedResponse.Data.Feed.ID)
fmt.Printf("Feed Group: %s\n", feedResponse.Data.Feed.GroupID)
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
use GetStream\GeneratedModels\CreateFeedGroupRequest;
use GetStream\GeneratedModels\ActivitySelectorConfig;
use GetStream\GeneratedModels\RankingConfig;
use GetStream\GeneratedModels\ActivityProcessorConfig;
use GetStream\GeneratedModels\GetOrCreateFeedRequest;

// Create feed group with activity processors, activity selectors, and ranking
$createFeedGroupRequest = new CreateFeedGroupRequest(
    id: "mytimeline",
    // Run the activity processors to analyse topics for text & images
    activityProcessors: [
        new ActivityProcessorConfig(type: "text_interest_tags"),
        new ActivityProcessorConfig(type: "image_interest_tags"),
    ],
    // 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: [
        new ActivitySelectorConfig(type: "popular"),
        new ActivitySelectorConfig(type: "following"),
        new ActivitySelectorConfig(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: new RankingConfig(
        type: "interest",
        score: "decay_linear(time) * interest_score * decay_linear(popularity)"
    )
);

// Create the feed group
$response = $feedsClient->createFeedGroup($createFeedGroupRequest);

// Create and get the feed for a specific user
$forYouFeed = $feedsClient->feed("mytimeline", "thierry");
$feedRequest = new GetOrCreateFeedRequest(userID: "thierry");
$feedResponse = $forYouFeed->getOrCreateFeed($feedRequest);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

# Create feed group with activity processors, activity selectors, and ranking
create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: "mytimeline",
  activity_processors: [
    GetStream::Generated::Models::ActivityProcessorConfig.new(type: "text_interest_tags"),
    GetStream::Generated::Models::ActivityProcessorConfig.new(type: "image_interest_tags")
  ],
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(type: "popular"),
    GetStream::Generated::Models::ActivitySelectorConfig.new(type: "following"),
    GetStream::Generated::Models::ActivitySelectorConfig.new(type: "interest")
  ],
  ranking: GetStream::Generated::Models::RankingConfig.new(
    type: "interest",
    score: "decay_linear(time) * interest_score * decay_linear(popularity)"
  )
)

client.feeds.create_feed_group(create_request)

# Create and get the feed for a specific user
get_or_create_request = GetStream::Generated::Models::GetOrCreateFeedRequest.new(
  user_id: "thierry"
)
feed_response = client.feeds.get_or_create_feed("mytimeline", "thierry", get_or_create_request)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
import io.getstream.services.FeedsImpl;
import io.getstream.models.*;

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

CreateFeedGroupRequest createRequest = CreateFeedGroupRequest.builder()
    .id("mytimeline")
    .activityProcessors(List.of(
        ActivityProcessorConfig.builder().type("text_interest_tags").build(),
        ActivityProcessorConfig.builder().type("image_interest_tags").build()
    ))
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("popular").build(),
        ActivitySelectorConfig.builder().type("following").build(),
        ActivitySelectorConfig.builder().type("interest").build()
    ))
    .ranking(RankingConfig.builder()
        .type("interest")
        .score("decay_linear(time) * interest_score * decay_linear(popularity)")
        .build())
    .build();

CreateFeedGroupResponse response = feedsClient.createFeedGroup(createRequest).execute().getData();

// Create and get the feed for a specific user
Feed forYouFeed = new Feed("mytimeline", "thierry", feedsClient);
GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder()
    .userID("thierry")
    .build();
forYouFeed.getOrCreate(feedRequest);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var createRequest = new CreateFeedGroupRequest
{
    ID = "mytimeline",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "text_interest_tags" },
        new() { Type = "image_interest_tags" }
    },
    ActivitySelectors = new List<ActivitySelectorConfig>
    {
        new() { Type = "popular" },
        new() { Type = "following" },
        new() { Type = "interest" }
    },
    Ranking = new RankingConfig
    {
        Type = "interest",
        Score = "decay_linear(time) * interest_score * decay_linear(popularity)"
    }
};

var response = await _feedsV3Client.CreateFeedGroupAsync(createRequest);

// Create and get the feed for a specific user
await _feedsV3Client.GetOrCreateFeedAsync(
    "mytimeline",
    "thierry",
    new GetOrCreateFeedRequest { UserID = "thierry" }
);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
create_request = {
    "id": "mytimeline",
    "activity_processors": [
        {"type": "text_interest_tags"},
        {"type": "image_interest_tags"}
    ],
    "activity_selectors": [
        {"type": "popular"},
        {"type": "following"},
        {"type": "interest"}
    ],
    "ranking": {
        "type": "interest",
        "score": "decay_linear(time) * interest_score * decay_linear(popularity)"
    }
}

response = self.client.feeds.create_feed_group(**create_request)

# Create and get the feed for a specific user
feed = self.client.feeds.feed("mytimeline", "thierry")
feed.get_or_create(user_id="thierry")
```

</codetabs-item>

</codetabs>

## 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:

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
const myNotificationGrpup = await serverClient.feeds.createFeedGroup({
  id: "myid",
  // Group by activity type and day
  aggregation: { format: '{{ type }}-{{ time.strftime("%Y-%m-%d") }}' },
  // Enable notification tracking
  notification: {
    track_read: true,
    track_seen: true,
  },
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
myNotificationGroup, err := client.Feeds().CreateFeedGroup(context.Background(), &getstream.CreateFeedGroupRequest{
    ID: "myid2",
    // Group by activity type and day
    Aggregation: &getstream.AggregationConfig{
        Format: getstream.PtrTo("{{ type }}-{{ time.strftime(\"%Y-%m-%d\") }}"),
    },
    // Enable notification tracking
    Notification: &getstream.NotificationConfig{
        TrackRead: getstream.PtrTo(true),
        TrackSeen: getstream.PtrTo(true),
    },
})
if err != nil {
    log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
// Create notification feed group with aggregation and tracking
$request = new GeneratedModels\CreateFeedGroupRequest(
    id: "myid",
    defaultVisibility: 'public',
    // Group by activity type and day
    aggregation: new GeneratedModels\AggregationConfig(
        format: '{{ type }}-{{ time.strftime("%Y-%m-%d") }}'
    ),
    // Enable notification tracking
    notification: new GeneratedModels\NotificationConfig(
        trackRead: true,
        trackSeen: true
    )
);

// Create the feed group
$response = $feedsClient->createFeedGroup($request);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = "aggregated-group",
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    },
    Aggregation = new AggregationConfig
    {
        Format = "{{ type }}-{{ time.strftime(\"%Y-%m-%d\") }}"
    }
});
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
self.client.feeds.create_feed_group(
    id = feed_group_id,
    default_visibility="public",
    activity_processors=[
        ActivityProcessorConfig(type="default")
    ],
    aggregation=AggregationConfig(
        format="{{ type }}-{{ time.strftime(\"%Y-%m-%d\") }}"
    )
)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

my_notification_group = client.feeds.create_feed_group(
  GetStream::Generated::Models::CreateFeedGroupRequest.new(
    id: 'myid',
    # Group by activity type and day
    aggregation: GetStream::Generated::Models::AggregationConfig.new(
      format: '{{ type }}-{{ time.strftime("%Y-%m-%d") }}'
    ),
    # Enable notification tracking
    notification: GetStream::Generated::Models::NotificationConfig.new(
      track_read: true,
      track_seen: true
    )
  )
)
```

</codetabs-item>

</codetabs>


### Notification Feed Example

The built-in `notification` feed comes with the necessary configurations:

<codetabs>

<codetabs-item value="swift" label="Swift">

```swift
let notificationFeed = client.feed(group: "notification", id: "jane")
let notifications = try await notificationFeed.getOrCreate()
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val notificationFeed = client.feed(group = "notification", id = "jane")
val notifications = notificationFeed.getOrCreate()
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
// Read notifications
await notificationFeed.getOrCreate({
  limit: 20,
});
console.log(notificationFeed.currentState.is_loading_activities);
console.log(notificationFeed.currentState.aggregated_activities);

await notificationFeed.getNextPage();
```

</codetabs-item>

<codetabs-item value="react" label="React">

```js
const notificationFeed = client.feed("notification", "jane");

await notificationFeed.getOrCreate({
  limit: 20,
});

const { aggregated_activities, isLoading, hasNextPage, loadNextPage } =
  useAggregatedActivities(feed) ?? {};
```

</codetabs-item>

<codetabs-item value="reactnative" label="React Native">

```js
const notificationFeed = client.feed("notification", "jane");

await notificationFeed.getOrCreate({
  limit: 20,
});

const { aggregated_activities, isLoading, hasNextPage, loadNextPage } =
  useAggregatedActivities(feed) ?? {};
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final notificationFeed = client.feed(group: 'notification', id: 'john');
await notificationFeed.getOrCreate();
```

</codetabs-item>

<codetabs-item value="nodejs" label="Node">

```js
const notificationFeed = client.feed("notification", "jane");

// Read notifications
const notifications = (
  await notificationFeed.getOrCreate({
    limit: 20,
    user_id: "<user_id>",
  })
).aggregated_activities;
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
notificationFeed := client.Feeds().Feed("notification", "john")
// Read notifications
response, err := notificationFeed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
  Limit:  getstream.PtrTo(20),
  UserID: getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal(err)
}
log.Printf("Response: %+v\n", response.Data.AggregatedActivities)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```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();
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
use GetStream\GeneratedModels\GetOrCreateFeedRequest;

$notificationFeed = $feedsClient->feed("notification", "jane");

// Read notifications
$feedRequest = new GetOrCreateFeedRequest(
    limit: 20,
    userID: "jane"
);

$response = $notificationFeed->getOrCreateFeed($feedRequest);

// Access the aggregated activities
$notifications = $response->data->aggregatedActivities;
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
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 }
);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

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

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

# Get or create notification feed
notification_feed_request = GetStream::Generated::Models::GetOrCreateFeedRequest.new(
  limit: 20,
  user_id: 'jane'
)

response = client.feeds.get_or_create_feed('notification', 'jane', notification_feed_request)

# Access the aggregated activities
notifications = response.aggregated_activities if response.respond_to?(:aggregated_activities)
```

</codetabs-item>

</codetabs>


### Marking Notifications as Read

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
notificationFeed.markActivity(
    request = MarkActivityRequest(
        // Mark all notifications as read...
        markAllRead = true,
        // ...or only selected ones
        markRead = listOf(
            /* group names to mark as read */
        )
    )
)
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
await notificationFeed.markActivity({
  // Mark all notifications as read...
  mark_all_read: true,
  // ...or only selected ones
  mark_read: [
    /* group names to mark as read */
  ],
});
```

</codetabs-item>

<codetabs-item value="react" label="React">

```js
await notificationFeed.markActivity({
  // Mark all notifications as read...
  mark_all_read: true,
  // ...or only selected ones
  mark_read: [
    /* group names to mark as read */
  ],
});
```

</codetabs-item>

<codetabs-item value="reactnative" label="React Native">

```js
await notificationFeed.markActivity({
  // Mark all notifications as read...
  mark_all_read: true,
  // ...or only selected ones
  mark_read: [
    /* group names to mark as read */
  ],
});
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
await notificationFeed.markActivity(
  request: const MarkActivityRequest(
    // Mark all notifications as read...
    markAllRead: true,
    // ...or only selected ones
    markRead: [
      // group names to mark as read
    ],
  ),
);
```

</codetabs-item>

<codetabs-item value="node" label="Node">

```js
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>",
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
notificationFeed := client.Feeds().Feed("notification", "john")

_, err = notificationFeed.MarkActivity(context.Background(), &getstream.MarkActivityRequest{
  // Mark all notifications as read...
  MarkAllRead: getstream.PtrTo(true),
  // ...or only selected ones
  MarkRead: []string{
    // group names to mark as read
  },
  UserID:      getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error:", err)
}
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
use GetStream\GeneratedModels\MarkActivityRequest;

// Create notification feed
$notificationFeed = $feedsClient->feed("notification", "john");

// Mark all notifications as read
$markRequest = new MarkActivityRequest(
    markAllRead: true,
    userID: "john"
);

$response = $notificationFeed->markActivity($markRequest);

// Or mark only selected notifications as read
$markSelectedRequest = new MarkActivityRequest(
    markRead: [
        // group names to mark as read
    ],
    userID: "john"
);

$response = $notificationFeed->markActivity($markSelectedRequest);
```

</codetabs-item>

</codetabs>


## Updating feed groups

It's possible to update any custom or built-in feed group:

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
await client.feeds.updateFeedGroup({
  id: "<id of feed group to update>",
  // Fields to update
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
_, err = client.Feeds().UpdateFeedGroup(context.Background(), "myid", &getstream.UpdateFeedGroupRequest{
    // Fields to update
})
if err != nil {
    log.Fatal("Error updating feed group:", err)
}
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
use GetStream\GeneratedModels\UpdateFeedGroupRequest;

// Create update request
$updateRequest = new UpdateFeedGroupRequest(
    // Fields to update
    // activityProcessors: [...],
    // activitySelectors: [...],
    // ranking: new RankingConfig(...),
    // custom: (object) [...]
);

// Update the feed group
$response = $feedsClient->updateFeedGroup("myid", $updateRequest);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

update_request = GetStream::Generated::Models::UpdateFeedGroupRequest.new(
  # Fields to update, e.g.:
  # activity_processors: [...],
  # activity_selectors: [...],
  # ranking: GetStream::Generated::Models::RankingConfig.new(...),
  # custom: { ... }
)

response = client.feeds.update_feed_group("myid", update_request)
```

</codetabs-item>

</codetabs>


## Deleting feed groups

Deleting feed groups will not cascade delete associated resources. It will make feeds within the feed group unreadable but any fanout that has happened before deletion will stay in effect.

If you need a clean slate during development it is advised to create a new feed group instead.

<codetabs>

<codetabs-item value="nodejs" label="Node">

```js
await serverClient.feeds.deleteFeedGroup({
  id: "<feed group id to delete>",
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
_, err = client.Feeds().DeleteFeedGroup(context.Background(), "mytimeline", &getstream.DeleteFeedGroupRequest{})
```

</codetabs-item>

<codetabs-item value="php" label="php">

```php
// Delete the feed group (soft delete by default)
$response = $feedsClient->deleteFeedGroup("mytimeline", false);

// For hard delete, pass true as the second parameter
// $response = $feedsClient->deleteFeedGroup("mytimeline", true);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```rb
require 'getstream_ruby'

# Soft delete (default)
client.feeds.delete_feed_group("mytimeline", false)

# Hard delete
# client.feeds.delete_feed_group("mytimeline", true)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
import io.getstream.services.FeedsImpl;

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

// Soft delete (default)
DeleteFeedGroupResponse response = feedsClient.deleteFeedGroup("mytimeline", false).execute().getData();

// Hard delete
// DeleteFeedGroupResponse response = feedsClient.deleteFeedGroup("mytimeline", true).execute().getData();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Soft delete (default)
var response = await _feedsV3Client.DeleteFeedGroupAsync("mytimeline", false);

// Hard delete
// var response = await _feedsV3Client.DeleteFeedGroupAsync("mytimeline", true);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Soft delete (default)
response = self.client.feeds.delete_feed_group("mytimeline", hard_delete=False)

# Hard delete
# response = self.client.feeds.delete_feed_group("mytimeline", hard_delete=True)
```

</codetabs-item>

</codetabs>


---

This page was last updated at 2026-04-17T17:33:28.417Z.

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