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

>
> **Info:** Each activity selector selects the first 1000 activities that match its selection criteria.
>
> If `cutoff_window` is not set (and the selector has no built-in default — see the parameter tables below), no time-based filter is applied. The selector returns the latest 1000 matching activities regardless of when they were created — effectively `cutoff_window = infinity`, capped only by the 1000-activity limit.
>
> The minimum accepted value for `cutoff_window` is `1h`. Supported units are `s`, `m`, `h`, `d`, `w`, `y`. `cutoff_window` cannot be set together with `cutoff_time`.
>

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       |

This selector does not accept a [feed group scope](#feed-group-scope). It already reads exactly one feed, so scoping it to a set of feed groups is either a no-op or a request for "only the items here that were also cross-posted elsewhere", and it is rejected with a `400`.

#### Scope

The feed we're currently reading

#### Example

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

### 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       |
| `feed_groups`   | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups | -       | 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

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

### 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       |
| `feed_groups`             | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups                                                                        | -                  | No       |
| `ranking_candidate_limit` | integer, `1` to `1000`                            | On ranked feeds, the maximum number of candidates this selector contributes, see [Ranking candidate limit](#ranking-candidate-limit) | `1000`             | No       |

#### Scope

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

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

### 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       |
| `feed_groups`             | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups                                                                        | -            | No       |
| `ranking_candidate_limit` | integer, `1` to `1000`                            | On ranked feeds, the maximum number of candidates this selector contributes, see [Ranking candidate limit](#ranking-candidate-limit) | `1000`       | No       |

#### Scope

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

#### Example

```js label="JavaScript"
// 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
});
```

### 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. You can also seed and manage them through the API, see the [User interests](https://getstream.io/activity-feeds/docs/android/user-interests/) guide.

>
> **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](https://getstream.io/activity-feeds/docs/android/activity-processors/) or set when [creating an activity](https://getstream.io/activity-feeds/docs/android/activities/#overview-of-all-activity-fields).
>

#### 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       |
| `feed_groups`             | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups                                                                        | -                  | No       |
| `ranking_candidate_limit` | integer, `1` to `1000`                            | On ranked feeds, the maximum number of candidates this selector contributes, see [Ranking candidate limit](#ranking-candidate-limit) | `1000`             | No       |

#### Scope

Feeds that are visible to the logged-in user.

#### Examples

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

### 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       |
| `feed_groups`             | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups                                                                        | -                  | No       |
| `ranking_candidate_limit` | integer, `1` to `1000`                            | On ranked feeds, the maximum number of candidates this selector contributes, see [Ranking candidate limit](#ranking-candidate-limit) | `1000`             | No       |

#### Scope

Feeds that are visible to the logged-in user.

#### Example

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

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

>
> **Info:** This selector requires an authenticated user. It will return empty results for anonymous users.
>

#### 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-20)                                     | 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       |
| `feed_groups`         | object, see [Feed group scope](#feed-group-scope) | Limit selection to an included or excluded set of feed groups         | -                | No       |

>
> **Info:** **Fan-out limits.** To protect read performance, the `follow_suggestion` selector bounds how far it fans out:
>
> - **`max_suggested_feeds` has an effective ceiling of `20`.** A value above `20` runs at `20` (it is clamped, not rejected).
> - **`max_suggested_feeds × activities_per_feed` must not exceed `200`.** Creating or updating a feed group or view with a larger product is rejected with a `400`. Lower either value until the product is `≤ 200` — for example `max_suggested_feeds: 20` with `activities_per_feed: 10` (product `200`) is allowed, but `20 × 20 = 400` is not.
>

#### Scope

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

#### Example

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

## Selector parameters

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

### Sort

The following `sort` options are available:

>
> **Info:** Please note that sort options are only used to determine which activities are selected. The final activity order is determined by [ranking](https://getstream.io/activity-feeds/docs/node/custom-ranking/).
>

Fields:

- `created_at`
- `popularity`

Direction: `1` or `-1`

### Filters

The following `filter` options are available for the `following` selector:

| name          | type                      | description            | supported operations      | example                                                  |
| ------------- | ------------------------- | ---------------------- | ------------------------- | -------------------------------------------------------- |
| `id`          | string or list of strings | The ID of the activity | `$in`, `$eq`              | `{ id: { $in: [ 'abc', 'xyz' ] } }`                      |
| `filter_tags` | list of strings           | Tags for filtering     | `$eq`, `$contains`, `$in` | `{ filter_tags: { $in: [ 'categoryA', 'categoryB' ] } }` |

The following `filter` options are available for the `current`, `popular`, `interest`, `proximity` and `query` selectors:

| name            | type                                              | description                                                      | supported operations                       | example                                                                                      |
| --------------- | ------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------- |
| `id`            | string or list of strings                         | The ID of the activity                                           | `$in`, `$eq`                               | `{ id: { $in: [ 'abc', 'xyz' ] } }`                                                          |
| `activity_type` | string or list of strings                         | The type of the activity                                         | `$in`, `$eq`                               | `{ activity_type: { $in: [ 'abc', 'xyz' ] } }`                                               |
| `user_id`       | string or list of strings                         | The ID of the user who created the activity                      | `$in`, `$eq`                               | `{ user_id: { $in: [ 'abc', 'xyz' ] } }`                                                     |
| `text`          | string                                            | The text content of the activity                                 | `$eq`, `$q`, `$autocomplete`               | `{ text: { $q: 'popularity' } }`                                                             |
| `search_data`   | object                                            | The extra metadata for search indexing                           | `$contains`, `$path_exists`                | `{ search_data: { $contains: { 'category': 'sports', 'status': 'active' } } }`               |
| `interest_tags` | list of strings                                   | Tags for user interests                                          | `$eq`, `$contains`                         | `{ interest_tags: { $in: [ 'sports', 'music' ] } }`                                          |
| `filter_tags`   | list of strings                                   | Tags for filtering                                               | `$eq`, `$contains`, `$in`                  | `{ filter_tags: { $in: [ 'categoryA', 'categoryB' ] } }`                                     |
| `created_at`    | string, must be formatted as an RFC3339 timestamp | The time the activity was created                                | `$eq`, `$gt`, `$lt`, `$gte`, `$lte`        | `{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }`                                        |
| `popularity`    | number                                            | The popularity score of the activity                             | `$eq`, `$ne`, `$gt`, `$lt`, `$gte`, `$lte` | `{ popularity: { $gte: 70 } }`                                                               |
| `near`          | object                                            | GEO point and a distance (in km) to search for activities within | `$eq`                                      | `{ near: { $eq: { lat: 40.0, lng: -74.0, distance: 200 } } }`                                |
| `within_bounds` | object                                            | GEO bounds to search for activities within                       | `$eq`                                      | `{ within_bounds: { $eq: { ne_lat: 40.0, ne_lng: -115.0, sw_lat: 32.0, sw_lng: -125.0 } } }` |

When filtering by `filter_tags`, a plain array (or `$eq`) uses **AND-logic**: the activity must contain **all** of the specified tags. Use `$in` if you want **OR-logic**, where the activity must contain **any** of the specified tags.

The filter syntax also supports `$or` and `$and`:

```kotlin label="Kotlin"
// Get all the activities where filter tags contain both "green" and "orange"
val filter = Filters.and(
  ActivitiesFilterField.filterTags.`in`("green"),
  ActivitiesFilterField.filterTags.`in`("orange"),
)
```

```java label="Java"
// Get all the activities where filter tags contain both "green" and "orange"
Map<String, Object> filter = new HashMap<>();
List<Map<String, Object>> andConditions = List.of(
    Map.of("filter_tags", List.of("green")),
    Map.of("filter_tags", List.of("orange"))
);
filter.put("$and", andConditions);
```

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

### Feed group scope

`feed_groups` limits what a selector is allowed to discover to a set of feed groups. Set either `include` or `exclude`, never both.

| Name      | Type            | Description                                                                      |
| --------- | --------------- | -------------------------------------------------------------------------------- |
| `include` | list of strings | Select only activities that live in a feed belonging to one of these feed groups |
| `exclude` | list of strings | Select activities from every feed group except these                             |

Both lists hold feed group IDs (`campaigns`, `user`), not full feed IDs (`campaigns:123`).

Select only from the `campaigns` and `teams` groups:

```json
{ "type": "popular", "feed_groups": { "include": ["campaigns", "teams"] } }
```

Select from everything except the `drafts` group:

```json
{ "type": "popular", "feed_groups": { "exclude": ["drafts"] } }
```

The scope is optional, and a selector without it selects exactly what it selected before this field existed. It is supported on every selector except `current_feed`, which already reads a single feed.

```js label="Node.js"
await client.feeds.updateFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "popular",
      feed_groups: { exclude: ["drafts"] },
    },
  ],
});
```

#### Cross-posted activities

An activity can be posted to several feeds at once, and those feeds can belong to different feed groups. The two directions treat that case differently:

| Direction | Rule                                                                            | Effect                                                 |
| --------- | ------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `include` | Selected when **at least one** of the activity's feeds is in an included group  | Narrow. A new feed group is invisible until you add it |
| `exclude` | Dropped only when **every** one of the activity's feeds is in an excluded group | Broad. A new feed group is discoverable right away     |

So an activity cross-posted to an excluded group and to a group that is not excluded is still selected.

This is why `exclude` is the safer form to reach for. An `include` list fails closed: a feed group created after the list was written is invisible to that selector until every list naming its siblings is updated, and nothing warns you that it is missing.

#### The following selector matches the delivering feed

On the `following` selector the scope is evaluated against the feed the activity was delivered from, rather than against every feed the activity was posted to. For an activity that arrived through a follow, that is the followed feed that fanned it out. For an activity added directly to the feed being read, it is that feed itself.

For a timeline this is usually the reading you want ("don't show me anything that came from `drafts`"), but it has two consequences:

- A cross-posted activity can be admitted by a `popular` selector and dropped by a `following` selector in the same feed.
- The feed's own group counts as a source. An `include` list that does not name the group of the feed being read drops the activities posted directly to that feed, and an `exclude` list that names that group drops them too. A `timeline` feed whose `following` selector carries `{ "include": ["user"] }` shows what the user follows and nothing that was posted to the timeline itself. Add `timeline` to the list to keep those.

#### follow_suggestion only draws from the `user` group

The follow suggestion algorithm only ever suggests feeds in the `user` feed group, so a scope on that selector is either a no-op or a selector that can never return anything. The two shapes that can never return anything are rejected with a `400`:

| Scope on `follow_suggestion` | Result                |
| ---------------------------- | --------------------- |
| `include` contains `user`    | Accepted, no effect   |
| `include` without `user`     | Rejected with a `400` |
| `exclude` contains `user`    | Rejected with a `400` |
| `exclude` without `user`     | Accepted, no effect   |

So an `exclude` list naming other groups stays valid on this selector, and one scope can be applied to every selector in a view. An `include` list has to name `user` alongside the other groups, or the selector has to be dropped from that view.

#### Limits and validation

- One direction per selector. Sending both `include` and `exclude` is rejected with a `400`.
- At most **20** feed groups per list.
- Entries cannot be blank, and cannot repeat within a list.
- `feed_groups` on a `current_feed` selector is rejected with a `400`.
- On a `follow_suggestion` selector, a scope that rules out the `user` feed group is rejected with a `400`, because that selector could then never return anything. See the section above.
- Feed group IDs are **not** checked against the feed groups that exist, so an `exclude` list can name a group before you create it. The trade-off is that a typo in an `include` list is accepted and quietly narrows or empties that selector.

#### Performance

A scope that keeps most of the candidate activities is effectively free, and an `exclude` list that removes a small group can make the read slightly cheaper. A scope that rejects almost everything is not: the selector has to walk much further down the candidate set to fill a page, and the read gets slower while returning few activities, or none.

The direction is not what predicts the cost, the surviving volume is. A long `exclude` list that removes the groups holding most of the popular content is just as expensive as a narrow `include` list.

Keep scope lists short, and avoid scoping away the feed groups that hold most of the content the selector is meant to surface.

#### Hot feed cache

A feed group or view where any selector carries a `feed_groups` scope is not eligible for [hot feed cache](https://getstream.io/activity-feeds/docs/node/hot-feed-cache/). Those reads fall back to a normal feed read, with no error.

### Ranking candidate limit

On a feed with [custom ranking](https://getstream.io/activity-feeds/docs/node/custom-ranking/), every selector contributes up to 1000 candidate activities, and ranking then scores the whole pool. `ranking_candidate_limit` lowers that number for one selector.

A smaller pool makes the selector cheaper to run. This matters most for selectors that have to skip many activities the reader can't see, like a `proximity` selector in an area where most nearby activities are in private feeds. It also lets you balance a mix of selectors, for example a few nearby activities blended into a larger pool of popular ones.

```json
{ "type": "popular", "ranking_candidate_limit": 200 }
```

- Accepted values are `1` to `1000`. Leave it out to use the default of `1000`.
- Supported on `popular`, `proximity`, `interest` and `query`. Setting it on `following`, `current_feed` or `follow_suggestion` is rejected with a `400`.
- It only applies to feeds with ranking. A feed without ranking already reads page-sized batches, so the field has no effect there.
- It keeps the first N activities in the selector's own order, not the best N by ranking score. `proximity` orders by recency, so a limit of `100` keeps the 100 most recent nearby activities, not the 100 closest.
- The first page of a ranked feed is cached. After you change the limit, a cached first page can take up to an hour to reflect it.

```js label="Node.js"
await client.feeds.updateFeedGroup({
  id: "myid",
  activity_selectors: [
    {
      type: "popular",
      ranking_candidate_limit: 200,
    },
  ],
});
```

## 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. On a ranked feed you can lower an individual selector's share with [`ranking_candidate_limit`](#ranking-candidate-limit).

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.

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

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

Feed groups let you define what activities should be included in the feed and the ranking to sort these activities.

By default all feeds in the given group will have the same settings. However, you might want to experiment with different selectors and rankings. Feed views let you do that by overriding the group's default settings.

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

---

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