$createResponse = $feedsClient->createFeedGroup(
new GeneratedModels\CreateFeedGroupRequest(
id: $feedGroupId,
defaultVisibility: 'public',
activityProcessors: [
['type' => 'text_interest_tags']
]
)
);Processors
Activity processors enable you to do additional processing on activities after they are posted.
Supported activity processors:
| Type | Description |
|---|---|
text_interest_tags | Analyzes text content to extract topics |
image_interest_tags | Analyzes image attachments to extract topics |
og_metadata_enrichment | Analyzes Open Graph (OG) metadata of links in activity text to extract topic |
Processors use AI to extract topics from the given sources.
The topics of an activity are stored in the interest_tags field.
Topic information can be used to query activities or filter feeds based on topics.
Activity topics enable the Stream API to automatically compute users' interests (what activities a user interacts with). A user's interest can be used as input for activity selectors and ranking.
Topics can also be set explicitly with the create and update activity endpoints.
Setting up activity processors
You can set up activity processors on the feed group level:
You can also update built-in feed groups with activity processors:
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);Extraction thresholds
By default text_interest_tags runs on any activity that has text, however short. Very short posts tend to produce low-quality topics, and each one still costs an AI call. You can require a minimum amount of text before extraction runs:
| Field | Description |
|---|---|
min_text_length | Minimum number of characters the activity text must have. 0 (the default) disables it |
min_word_count | Minimum number of words the activity text must have. 0 (the default) disables it |
Both default to 0, so leaving them unset preserves the existing behaviour. When both are set, an activity must clear both to be processed. An activity below the threshold is stored as normal and keeps whatever interest_tags it was created with — no AI call is made for it, and no feeds.activity.updated event is emitted for topics.
The right threshold depends on your content: a handful of words can still be meaningful in some apps, so these are yours to tune rather than a fixed platform default.
Both fields apply only to text_interest_tags, the only processor that reads activity text.
$createResponse = $feedsClient->createFeedGroup(
new GeneratedModels\CreateFeedGroupRequest(
id: $feedGroupId,
defaultVisibility: 'public',
activityProcessors: [
[
'type' => 'text_interest_tags',
'min_text_length' => 40,
'min_word_count' => 5,
]
]
)
);Restricting topics to your own vocabulary
By default the processors write whatever topics the AI produces. You can bound that to a list you control, per feed group:
| Field | Description |
|---|---|
allowed_tags | The processors may only write topics from this list |
blocked_tags | These topics are never written, whatever the AI produced |
send_allowed_tags_to_ai | Give allowed_tags to the AI so it chooses from your list. Requires allowed_tags. Off by default |
allowed_tags and blocked_tags cannot both be set on one feed group: an allowlist already drops everything absent from it, so a blocklist alongside it would have no effect.
Topics are stored and matched lower-cased and trimmed, so Cycling and cycling are the same tag. A list can hold up to 1,000 tags and 15,000 characters in total.
These settings apply to text_interest_tags and image_interest_tags. og_metadata_enrichment is not affected: it extracts the publisher name and keywords from a link rather than choosing topics, so a vocabulary would discard nearly everything it produces.
Matching without send_allowed_tags_to_ai
With send_allowed_tags_to_ai off, the AI is never told about your list. It describes the activity in its own words, and a topic is written only when those words happen to match one of your tags exactly.
That happens less often than it sounds. A post about electric car deliveries usually produces electric vehicles, so an allowed_tags of ev keeps nothing. An image of a bicycle produces bicycle, so cycling keeps nothing.
If your list is a set of categories rather than the words the AI would use to describe the content, expect few or no topics.
Turning send_allowed_tags_to_ai on is the reliable way to use allowed_tags. The AI then picks from your list, so the same post comes back tagged ev and the same image cycling. Your list is sent with every request for the feed groups that enable it, so it adds a cost per activity. Leaving it off keeps that group's list out of the request.
$createResponse = $feedsClient->createFeedGroup(
new GeneratedModels\CreateFeedGroupRequest(
id: $feedGroupId,
defaultVisibility: 'public',
activityProcessors: [
['type' => 'text_interest_tags']
],
activityProcessing: [
'allowed_tags' => ['cycling', 'markets', 'cooking'],
'send_allowed_tags_to_ai' => true,
]
)
);Activities in more than one feed group
An activity has one set of interest_tags, not one per feed. When an activity is posted to feeds in several feed groups, the configuration of those groups is pooled: the allowed_tags of all of them form the permitted set, and the blocked_tags of all of them are applied on top of it.
Pooling is deliberately strict:
- A feed group that configured no list does not escape a sibling group's list.
- A topic blocked by one group stays blocked even where another group allows it.
- Only groups that actually run
text_interest_tagsorimage_interest_tagscontribute.
So the guarantee is "only the topics this application configured", not "only the topics this feed group configured". If a feed group's topics need to be independent of another's, do not post the same activity into both.
Notification activities
Activity processors never run on notification activities — the activities generated in a notification feed by follows, comments, reactions and mentions. They are created by the notification pipeline rather than the activity-creation path that runs processors, so they are never sent to an AI model and never receive interest_tags, regardless of what the notification feed group configures.
Reading topics
Whenever a new activity is posted, the processors will run. Interest topics are not computed instantly; they are added with the feeds.activity.updated event.
$activity = new GeneratedModels\AddActivityRequest(
type: 'post',
feeds: ['user:eric'],
text: 'check out my 10 fitness tips for reducing lower back pain',
userID: 'eric'
);
$response = $feedsClient->addActivity($activity);
// Wait for feeds.activity.updated event
$response->getData()->activity->interestTags // ["fitness", "health", "tips"]