# Activity selectors

Activity selectors give you control over which data is shown in a feed. For example you can decide to show only popular activities, or activities that fit the current user's interests.

<admonition type="info">

Each activity selector selects the first 1000 activities that match its selection criteria.

</admonition>

This page details what kind of activity selectors are supported by the Stream API, and how can you configure them.

You can create custom feed groups or update the built-in groups with your own activity selector configuration.

## Selector types

### Current Feed Selector

Shows activities from the current feed. This is the selector used when reading a `user` feed.

#### Parameters

| Name            | Type                               | Description                                         | Default      | Required |
| --------------- | ---------------------------------- | --------------------------------------------------- | ------------ | -------- |
| `sort`          | array, see [Sort](#sort)           | Sort options                                        | Newest first | No       |
| `filter`        | object, see [Filters](#filters)    | Additional filter conditions                        | -            | No       |
| `cutoff_window` | string, duration like `2h` or `5d` | Activities older than this window won't be selected | -            | No       |

#### Scope

The feed we're currently reading

#### Example

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "current_feed",
      // Optionally provide cutoff window
      cutoff_window: "10d",
    },
  ],
});
```

</codetabs-item>

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

```go
activitySelector := getstream.ActivitySelectorConfig{
  Type:             getstream.PtrTo("current_feed"),
  // Optionally provide cutoff window
  CutoffWindow: getstream.PtrTo("10d"),
}

request := &getstream.CreateFeedGroupRequest{
  ID:                "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{activitySelector},
}

ctx := context.Background()
response, err := client.Feeds().CreateFeedGroup(ctx, request)
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "current_feed",
                cutoffWindow: "10d"
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

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

```ruby
require 'getstream_ruby'

client = GetStreamRuby.manual(
  api_key: 'api_key',
  api_secret: 'api_secret'
)

create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: 'myid',
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(
      type: 'current_feed',
      cutoff_window: '10d'
    )
  ]
)

create_response = client.feeds.create_feed_group(create_request)
```

</codetabs-item>

</codetabs>

### Following Feed Selector

Shows activities from followed feeds and activities directly added to the feed being read. This is the selector used when reading a `timeline` feed.

#### Parameters

| Name            | Type                               | Description                                         | Default | Required |
| --------------- | ---------------------------------- | --------------------------------------------------- | ------- | -------- |
| `filter`        | object, see [Filters](#filters)    | Additional filter conditions                        | -       | No       |
| `cutoff_window` | string, duration like `2h` or `5d` | Activities older than this window won't be selected | -       | No       |

#### Scope

1 000 latest added activities from feeds followed by the feed we're currently reading, and activities posted to the current feed.

#### Example

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "following",
      // Optionally provide cutoff window
      cutoff_window: "10d",
    },
  ],
});
```

</codetabs-item>

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

```go
activitySelector := getstream.ActivitySelectorConfig{
  Type:             getstream.PtrTo("following"),
  // Optionally provide cutoff window
  CutoffWindow: getstream.PtrTo("10d"),
}

request := &getstream.CreateFeedGroupRequest{
  ID:                "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{activitySelector},
}

ctx := context.Background()
response, err := client.Feeds().CreateFeedGroup(ctx, request)
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "following",
                cutoffWindow: "10d"
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

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

```ruby
require 'getstream_ruby'

client = GetStreamRuby.manual(
  api_key: 'api_key',
  api_secret: 'api_secret'
)

create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: 'myid',
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(
      type: 'following',
      cutoff_window: '10d'
    )
  ]
)

create_response = client.feeds.create_feed_group(create_request)
```

</codetabs-item>

</codetabs>

### Popular Activity Selector

Selects popular activities from public and visible feeds.

Popularity is computed by the following formula:

```js
activity.popularity = reactions + comments * 2 + bookmarks * 3 + shares * 3;
```

#### Parameters

| Name             | Type                                        | Description                                               | Default            | Required |
| ---------------- | ------------------------------------------- | --------------------------------------------------------- | ------------------ | -------- |
| `sort`           | array, see [Sort](#sort)                    | Sort options                                              | Newest first       | No       |
| `filter`         | object, see [Filters](#filters)             | Additional filter conditions                              | -                  | No       |
| `min_popularity` | number (only positive numbers are accepted) | Minimum popularity an activity should have to be selected | `5`                | No       |
| `cutoff_window`  | string, duration like `2h` or `5d`          | Activities older than this window won't be selected       | `7d` (last 7 days) | No       |

#### Scope

Any feed with `public` or `visible` visibility level.

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "popular",
      // Optional parameters
      min_popularity: 70,
      cutoff_window: "10d",
    },
  ],
});
```

</codetabs-item>

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

```go
activitySelector := getstream.ActivitySelectorConfig{
  Type:             getstream.PtrTo("popular"),
  // Optional parameters
  CutoffWindow:     getstream.PtrTo("10d"),
  MinPopularity:    getstream.PtrTo(70),
}

request := &getstream.CreateFeedGroupRequest{
  ID:                "myid10",
  ActivitySelectors: []getstream.ActivitySelectorConfig{activitySelector},
}

ctx := context.Background()
response, err := client.Feeds().CreateFeedGroup(ctx, request)
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "popular",
                minPopularity: 70,
                cutoffWindow: "10d"
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

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

```ruby
require 'getstream_ruby'

client = GetStreamRuby.manual(
  api_key: 'api_key',
  api_secret: 'api_secret'
)

create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: 'myid',
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(
      type: 'popular',
      min_popularity: 70,
      cutoff_window: '10d'
    )
  ]
)

create_response = client.feeds.create_feed_group(create_request)
```

</codetabs-item>

</codetabs>

### Proximity Activity Selector

Shows activities based on geographic proximity

#### Parameters

| Name             | Type                                        | Description                                               | Default      | Required |
| ---------------- | ------------------------------------------- | --------------------------------------------------------- | ------------ | -------- |
| `sort`           | array, see [Sort](#sort)                    | Sort options                                              | Newest first | No       |
| `filter`         | object, see [Filters](#filters)             | Additional filter conditions                              | -            | No       |
| `cutoff_window`  | string, duration like `2h` or `5d`          | Activities older than this window won't be selected       | -            | No       |
| `min_popularity` | number (only positive numbers are accepted) | Minimum popularity an activity should have to be selected | `0`          | No       |

#### Scope

Any feed with `public` or `visible` visibility level.

#### Example

<codetabs>

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

```swift

```

</codetabs-item>

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

```js
// Provide filter when reading the feed
await feed.getOrCreate({
  filter: {
    within_bounds: {
      $eq: {
        ne_lat: 52.43017,
        ne_lng: 4.924821,
        sw_lat: 52.334272,
        sw_lng: 4.822116,
      },
    },
    // Optionally provide other filter properties, just like when querying activities
    activity_type: "hike",
  },
});

// Use either within_bounds or near filter
await feed.getOrCreate({
  filter: {
    near: { $eq: { lat: 52.373558, lng: 4.885261, distance: 10 } },
  },
});

// You can omit filter if location is set for user
const me = client.state.getLatestValue().connected_user;
await client.updateUsersPartial({
  users: [
    {
      id: me.id,
      set: {
        lat: 52.373558,
        lng: 4.885261,
      },
    },
  ],
});

await feed.getOrCreate({
  // If filter is not provided, but feed group has proximity selector, API searches based on user's location
});
```

</codetabs-item>

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

```js
// Provide filter when reading the feed
await feed.getOrCreate({
  filter: {
    within_bounds: {
      $eq: {
        ne_lat: 52.43017,
        ne_lng: 4.924821,
        sw_lat: 52.334272,
        sw_lng: 4.822116,
      },
    },
    // Optionally provide other filter properties, just like when querying activities
    activity_type: "hike",
  },
});

// Use either within_bounds or near filter
await feed.getOrCreate({
  filter: {
    near: { $eq: { lat: 52.373558, lng: 4.885261, distance: 10 } },
  },
});

// You can omit filter if location is set for user
const me = client.state.getLatestValue().connected_user;
await client.updateUsersPartial({
  users: [
    {
      id: me.id,
      set: {
        lat: 52.373558,
        lng: 4.885261,
      },
    },
  ],
});

await feed.getOrCreate({
  // If filter is not provided, but feed group has proximity selector, API searches based on user's location
});
```

</codetabs-item>

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

```js
// Provide filter when reading the feed
await feed.getOrCreate({
  filter: {
    within_bounds: {
      $eq: {
        ne_lat: 52.43017,
        ne_lng: 4.924821,
        sw_lat: 52.334272,
        sw_lng: 4.822116,
      },
    },
    // Optionally provide other filter properties, just like when querying activities
    activity_type: "hike",
  },
});

// Use either within_bounds or near filter
await feed.getOrCreate({
  filter: {
    near: { $eq: { lat: 52.373558, lng: 4.885261, distance: 10 } },
  },
});

// You can omit filter if location is set for user
const me = client.state.getLatestValue().connected_user;
await client.updateUsersPartial({
  users: [
    {
      id: me.id,
      set: {
        lat: 52.373558,
        lng: 4.885261,
      },
    },
  ],
});

await feed.getOrCreate({
  // If filter is not provided, but feed group has proximity selector, API searches based on user's location
});
```

</codetabs-item>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "proximity",
      // Optional parameters
      min_popularity: 40,
      cutoff_window: "1d",
    },
  ],
});

// Provide filter when reading the feed
await feed.getOrCreate({
  filter: {
    within_bounds: {
      $eq: {
        ne_lat: 52.43017,
        ne_lng: 4.924821,
        sw_lat: 52.334272,
        sw_lng: 4.822116,
      },
    },
  },
  user_id: "<user id>",
});

// Use either within_bounds or near filter
await feed.getOrCreate({
  filter: {
    near: { $eq: { lat: 52.373558, lng: 4.885261, distance: 10 } },
  },
  user_id: "<user id>",
});
```

</codetabs-item>

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

```go
activitySelector := getstream.ActivitySelectorConfig{
  Type:             getstream.PtrTo("proximity"),
  // Optional parameters
  CutoffWindow:     getstream.PtrTo("1d"),
  MinPopularity:    getstream.PtrTo(40),
}

request := &getstream.CreateFeedGroupRequest{
  ID:                "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{activitySelector},
}

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

// Reading feed
ctx := context.Background()
feed := client.Feeds().Feed("user", "john")
response, err := feed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
  Filter:  map[string]any{
    "within_bounds": map[string]any{
      "$eq": map[string]any{
        "ne_lat": 52.43017,
        "ne_lng": 4.924821,
        "sw_lat": 52.334272,
        "sw_lng": 4.822116,
      },
    },
  },
  UserID:  getstream.PtrTo("john"),
})
if err != nil {
  log.Fatal("Error:", err)
}

response, err = feed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
  Filter:  map[string]any{
    "near": map[string]any{
      "$eq": map[string]any{
        "lat":      52.373558,
        "lng":      4.885261,
        "distance": 10,
      },
    },
  },
  UserID:  getstream.PtrTo("john"),
})

if err != nil {
  log.Fatal("Error:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "proximity",
                minPopularity: 40,
                cutoffWindow: "1d",
            )
        ]
    )
);

// Provide filter when reading the feed
$feedResponse = $feedsClient->getOrCreateFeed(
    "myid",
    "user123",
    new GeneratedModels\GetOrCreateFeedRequest(
        filter: (object)[
            'within_bounds' => (object)[
                '$eq' => (object)[
                    'ne_lat' => 52.43017,
                    'ne_lng' => 4.924821,
                    'sw_lat' => 52.334272,
                    'sw_lng' => 4.822116,
                ]
            ]
        ],
        userID: "user123"
    )
);

// Use either within_bounds or near filter
$feedResponse2 = $feedsClient->getOrCreateFeed(
    "myid",
    "user123",
    new GeneratedModels\GetOrCreateFeedRequest(
        filter: (object)[
            'near' => (object)[
                '$eq' => (object)[
                    'lat' => 52.373558,
                    'lng' => 4.885261,
                    'distance' => 10
                ]
            ]
        ],
        userID: "user123"
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

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

```ruby
require 'getstream_ruby'

client = GetStreamRuby.manual(
  api_key: 'api_key',
  api_secret: 'api_secret'
)

create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: 'myid',
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(
      type: 'interest',
      sort: [{ field: 'popularity', direction: -1 }],
      filter: { activity_type: 'post' }
    )
  ]
)

create_response = client.feeds.create_feed_group(create_request)
```

</codetabs-item>

</codetabs>

### Interest Activity Selector

Selects activities that match the logged-in user's interests. Interests are automatically calculated for each user by Stream API based on which activities the user interacts with.

<admonition type="info">

Interests are based on activity topics. Topics are stored in the `interest_tags` field of an activity. It can be computed automatically using [activity processors](/activity-feeds/docs/<framework>/activity_processors/) or set when [creating an activity](/activity-feeds/docs/<framework>/activities/#overview-of-all-activity-fields).

</admonition>

#### Parameters

| Name             | Type                                        | Description                                               | Default            | Required |
| ---------------- | ------------------------------------------- | --------------------------------------------------------- | ------------------ | -------- |
| `sort`           | array, see [Sort](#sort)                    | Sort options                                              | Newest first       | No       |
| `filter`         | object, see [Filters](#filters)             | Additional filter conditions                              | -                  | No       |
| `cutoff_window`  | string, duration like `2h` or `5d`          | Activities older than this window won't be selected       | `2d` (last 2 days) | No       |
| `min_popularity` | number (only positive numbers are accepted) | Minimum popularity an activity should have to be selected | `0`                | No       |

#### Scope

Feeds that are visible to the logged-in user.

#### Examples

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "interest",
      // Optional parameters
      sort: [{ field: "popularity", direction: -1 }],
      filter: {
        activity_type: "post",
      },
    },
  ],
});
```

</codetabs-item>

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

```go
response, err := client.Feeds().CreateFeedGroup(context.Background(), &getstream.CreateFeedGroupRequest{
  ID: "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{
    {
      Type: getstream.PtrTo("interest"),
      // Optional parameters
      Sort: []getstream.SortParam{
        {
          Field:     getstream.PtrTo("popularity"),
          Direction: getstream.PtrTo(-1),
        },
      },
      Filter: map[string]any{
        "activity_type": "post",
      },
    },
  },
})
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "interest",
                sort: [
                    ['field' => 'popularity', 'direction' => -1]
                ],
                filter: (object)[
                    'activity_type' => 'post'
                ]
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

</codetabs>

### Query Activity Selector

Selects activities using the provided filter query.

#### Parameters

| Name            | Type                               | Description                                         | Default            | Required |
| --------------- | ---------------------------------- | --------------------------------------------------- | ------------------ | -------- |
| `sort`          | array, see [Sort](#sort)           | Sort options                                        | Newest first       | No       |
| `filter`        | object, see [Filters](#filters)    | Additional filter conditions                        | -                  | No       |
| `cutoff_window` | string, duration like `2h` or `5d` | Activities older than this window won't be selected | `7d` (last 7 days) | No       |

#### Scope

Feeds that are visible to the logged-in user.

#### Example

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "query",
      filter: { search_data: { $contains: { workout_type: "hike" } } },
      // Optional parameters
      sort: [{ field: "created_at", direction: -1 }],
    },
  ],
});
```

</codetabs-item>

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

```go
response, err := client.Feeds().CreateFeedGroup(context.Background(), &getstream.CreateFeedGroupRequest{
  ID: "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{
    {
      Type: getstream.PtrTo("query"),
      Filter: map[string]any{
        "search_data": map[string]any{
          "$contains": map[string]any{
            "workout_type": "hike",
          },
        },
      },
      // Optional parameters
      Sort: []getstream.SortParam{
        {
          Field:     getstream.PtrTo("created_at"),
          Direction: getstream.PtrTo(-1),
        },
      },
    },
  },
})
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "query",
                filter: (object)[
                    'search_data' => (object)[
                        '$contains' => (object)[
                            'workout_type' => 'hike'
                        ]
                    ]
                ],
                sort: [
                    ['field' => 'created_at', 'direction' => -1]
                ]
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

</codetabs>

### Follow Suggestion Activity Selector

Selects activities from feeds that are suggested to the user based on follow suggestions. This selector uses Stream's intelligent follow suggestion algorithm to discover relevant content from feeds the user might want to follow.

<admonition type="info">

This selector requires an authenticated user. It will return empty results for anonymous users.

</admonition>

#### Parameters

| Name                  | Type                                        | Description                                                           | Default          | Required |
| --------------------- | ------------------------------------------- | --------------------------------------------------------------------- | ---------------- | -------- |
| `sort`                | array, see [Sort](#sort)                    | Sort options                                                          | Popularity first | No       |
| `cutoff_window`       | string, duration like `2h` or `5d`          | Activities older than this window won't be selected                   | -                | No       |
| `min_popularity`      | number (only positive numbers are accepted) | Minimum popularity an activity should have to be selected             | `5`              | No       |
| `activities_per_feed` | number (1-100)                              | Number of activities to select from each suggested feed               | `2`              | No       |
| `max_suggested_feeds` | number (1-50)                               | Maximum number of suggested feeds to consider                         | `10`             | No       |
| `min_feed_score`      | number (0.0-1.0)                            | Minimum recommendation score for a feed to be included in suggestions | `0.3`            | No       |

#### Scope

Activities from user feeds that are suggested based on the [follow suggestion algorithm](/activity-feeds/docs/<framework>/follows/#follow-suggestions). The selector always suggests feeds from the "user" feed group, regardless of which feed group is being viewed.

#### Example

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "follow_suggestion",
      // Optional parameters
      min_popularity: 10,
      cutoff_window: "10d",
      params: {
        activities_per_feed: 3,
        max_suggested_feeds: 15,
        min_feed_score: 0.4,
      },
    },
  ],
});
```

</codetabs-item>

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

```go
activitySelector := getstream.ActivitySelectorConfig{
  Type:             getstream.PtrTo("follow_suggestion"),
  // Optional parameters
  CutoffWindow:     getstream.PtrTo("10d"),
  MinPopularity:    getstream.PtrTo(10),
  Params: map[string]any{
    "activities_per_feed": 3,
    "max_suggested_feeds": 15,
    "min_feed_score": 0.4,
  },
}

request := &getstream.CreateFeedGroupRequest{
  ID:                "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{activitySelector},
}

ctx := context.Background()
response, err := client.Feeds().CreateFeedGroup(ctx, request)
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

```php
$createResponse = $feedsClient->createFeedGroup(
    new GeneratedModels\CreateFeedGroupRequest(
        id: "myid",
        activitySelectors: [
            new GeneratedModels\ActivitySelectorConfig(
                type: "follow_suggestion",
                minPopularity: 10,
                cutoffWindow: "10d",
                params: (object)[
                    'activities_per_feed' => 3,
                    'max_suggested_feeds' => 15,
                    'min_feed_score' => 0.4
                ]
            )
        ]
    )
);
```

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivitySelectors = new List<ActivitySelectorConfig>
    {
        new ActivitySelectorConfig
        {
            Type = "follow_suggestion",
            MinPopularity = 10,
            CutoffWindow = "10d",
            Params = new Dictionary<string, object>
            {
                { "activities_per_feed", 3 },
                { "max_suggested_feeds", 15 },
                { "min_feed_score", 0.4 }
            }
        }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id="myid",
    activity_selectors=[
        {
            "type": "follow_suggestion",
            "min_popularity": 10,
            "cutoff_window": "10d",
            "params": {
                "activities_per_feed": 3,
                "max_suggested_feeds": 15,
                "min_feed_score": 0.4,
            },
        }
    ],
)
```

</codetabs-item>

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

```ruby
require 'getstream_ruby'

client = GetStreamRuby.manual(
  api_key: 'api_key',
  api_secret: 'api_secret'
)

create_request = GetStream::Generated::Models::CreateFeedGroupRequest.new(
  id: 'myid',
  activity_selectors: [
    GetStream::Generated::Models::ActivitySelectorConfig.new(
      type: 'follow_suggestion',
      min_popularity: 10,
      cutoff_window: '10d',
      params: {
        activities_per_feed: 3,
        max_suggested_feeds: 15,
        min_feed_score: 0.4
      }
    )
  ]
)

create_response = client.feeds.create_feed_group(create_request)
```

</codetabs-item>

</codetabs>

## Selector parameters

Supported values for `sort` and `filter` objects.

### Sort

The following `sort` options are available:

<admonition type="info">

Please note that sort options are only used to determine which activities are selected. The final activity order is determined by [ranking](/activity-feeds/docs/<framework>/custom_ranking/).

</admonition>

<partial id="activity-feeds/v3-latest/_default/_partials/activities-sort-fields"></partial>

### Filters

<partial id="activity-feeds/v3-latest/_default/_partials/feed-filters"></partial>

It's also possible to provide filters when reading a feed. When providing `filter` to read a feed, group-level filters are ignored.

## Combining selectors

You can combine multiple selectors. The example below will include:

- popular activities from public and visible feeds
- activities from feeds the user follows
- activities from feeds the user has access to, and match the user's interest

Each activity selector selects the first 1000 activities that match its selection criteria. We suggest taking adventage of the different config options for the selectors to make sure that the selectors return the most relevant activities. When combining selectors, every selector runs independently, so in this case 3 \* 1000 activities can be selected.

Once selectors run, ranking is applied to the activities that are returned by the selectors. Even if you have multiple selectors, ranking only runs once.

You can't use more than 3 selectors in a feed group/view configuration.

<codetabs>

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

```js
const response = await client.feeds.createFeedGroup({
  id: "myid",
  activity_selectors: [
    { type: "popular" },
    { type: "following" },
    { type: "interest" },
  ],

  ranking: { type: "expression", score: "decay_linear(time) * popularity" },
});
```

</codetabs-item>

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

```go
response, err := client.Feeds().CreateFeedGroup(context.Background(), &getstream.CreateFeedGroupRequest{
  ID: "myid",
  ActivitySelectors: []getstream.ActivitySelectorConfig{
    {
      Type: getstream.PtrTo("popular"),
    },
    {
      Type: getstream.PtrTo("following"),
    },
    {
      Type: getstream.PtrTo("interest"),
    },
  },
  Ranking: &getstream.RankingConfig{
    Type: getstream.PtrTo("expression"),
    Score: getstream.PtrTo("decay_linear(time) * popularity"),
  },
})
if err != nil {
  log.Fatal("Error creating feed group:", err)
}
```

</codetabs-item>

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

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

</codetabs-item>

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

```csharp
var createResponse = await _feedsV3Client.CreateFeedGroupAsync(new CreateFeedGroupRequest
{
    ID = feedGroupId,
    DefaultVisibility = "public",
    ActivityProcessors = new List<ActivityProcessorConfig>
    {
        new() { Type = "default" }
    }
});
```

</codetabs-item>

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

```python
create_response = self.client.feeds.create_feed_group(
    id=feed_group_id,
    default_visibility="public",
)
```

</codetabs-item>

</codetabs>

## Real-time updates for activity selectors

For activities selected by `current` and `following` selectors WebSocket events are delivered to clients (as long as `watch: true` is used to read the feed). However, for activities selected by other selectors, WebSocket events are not delivered. This means you won't be receiving `activity.new` events, or updates if other users like/comment/etc. on the activity.

If you combine activity selectors, you'll be still receiving WebSocket events for activities selected by `current` and `following` selectors.

## Experimenting with selectors

<partial id="activity-feeds/v3-latest/_default/_partials/feed-view-intro"></partial>


---

This page was last updated at 2026-03-05T19:00:52.910Z.

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