Collections provide a way to attach data to activities that is shared between these activities and can be updated in a single place.
A typical use case is to track the status of an activity such as started, completed, or failed. Instead of having to update multiple activities when the status changes you can create a collection and add it to the activities that needs this data. When the status changes you only need to update the collection.
A collection consists of a name, an id and some data. You can think of the name as a namespace for the collection. A collection reference is a string that looks like <name>:<id> and is the unique identifier for the collection.
Data stored in collections can not be used in custom ranking or aggregation.
The batch endpoints supports up to 100 collections in a single request.
Automatic deduplication will be applied, keeping the last occurrence only.
The example below shows how to create a collection.
let response = try await client.createCollections( request: .init( collections: [ .init( name: "movies", id: "lord_of_the_rings", custom: [ "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 ] ) ] ))
val response: Result<List<CollectionData>> = client.createCollections( request = CreateCollectionsRequest( collections = listOf( CollectionRequest( name = "movies", id = "lord_of_the_rings", custom = mapOf( "title" to "Lord of the Rings", "genre" to "fantasy", "rating" to 9 ) ) ) ))
The example below shows how to update a collection.
let response = try await client.updateCollections( request: .init( collections: [ .init( name: "movies", id: "lord_of_the_rings", custom: [ "title": "Lord of the Rings", "genre": "fantasy", "rating": 9.5 ] ) ] ))
val response: Result<List<CollectionData>> = client.updateCollections( request = UpdateCollectionsRequest( collections = listOf( UpdateCollectionRequest( name = "movies", id = "lord_of_the_rings", custom = mapOf( "title" to "Lord of the Rings", "genre" to "fantasy", "rating" to 9.5 ) ) ) ))
The upsert endpoint creates a collection if it does not exist, or updates it if it already exists. This is useful when you want to ensure a collection is in a specific state without checking for its existence first.
The upsert collections endpoint is server-side only.
Retrieve collection entries that match a filter, with sorting and cursor-based pagination. This is useful when you don't know the exact IDs of the entries you want (unlike readCollections, which fetches by reference). For example, listing every entry in a movies collection, or all entries owned by a given user.
queryCollections requires the read collections permission. When called client-side, results are automatically scoped to the calling user: only the user's own entries and global (no-owner) entries are returned, and any user_id filter is ignored.
let query = CollectionsQuery( filter: .equal(.name, "movies"), sort: [Sort(field: .createdAt, direction: .reverse)], limit: 10)let collectionList = client.collectionList(for: query)let response = try await collectionList.get()// response -> matching entries// collectionList.next -> cursor for the next page
val query = CollectionsQuery( filter = CollectionsFilterField.name.equal("movies"), sort = listOf(CollectionsSort(CollectionsSortField.CreatedAt, SortDirection.REVERSE)), limit = 10)val collectionList = client.collectionList(query = query)val response: Result<List<CollectionData>> = collectionList.get()// response -> matching entries// collectionList.next -> cursor for the next page
const response = await client.queryCollections({ filter: { name: "movies", }, sort: [{ field: "created_at", direction: -1 }], limit: 10,});// response.collections -> matching entries// response.next -> cursor for the next page (undefined on the last page)
const response = await client.queryCollections({ filter: { name: "movies", }, sort: [{ field: "created_at", direction: -1 }], limit: 10,});// response.collections -> matching entries// response.next -> cursor for the next page (undefined on the last page)
const response = await client.queryCollections({ filter: { name: "movies", }, sort: [{ field: "created_at", direction: -1 }], limit: 10,});// response.collections -> matching entries// response.next -> cursor for the next page (undefined on the last page)
Filters use Stream's standard query syntax. A bare value is an equality match ({ "name": "movies" }); operators are expressed as nested objects ({ "created_at": { "$gte": "2024-01-01T00:00:00Z" } }).
sort accepts one or more clauses of the form { field, direction }, where direction is 1 for ascending and -1 for descending. Sortable fields are created_at, updated_at, and id. When sort is omitted, entries are returned by created_at descending (newest first).
queryCollections is cursor-paginated. Each response includes a next cursor when more entries are available; pass it back as next to fetch the following page. next is absent on the last page. Keep the filter and sort identical across page requests.
let next;const all = [];do { const page = await client.queryCollections({ filter: { name: "movies" }, limit: 100, next, }); all.push(...page.collections); next = page.next;} while (next);
let response = try await feed.addActivity( request: .init( type: "post", text: "I love this movie!", collectionRefs: ["movies:lord_of_the_rings"] ))
val response: Result<ActivityData> = feed.addActivity( request = FeedAddActivityRequest( type = "post", text = "I love this movie!", collectionRefs = listOf("movies:lord_of_the_rings") ))
const response = await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});
const response = await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});
const response = await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});
const response = await client.feeds.addActivity({ type: 'post', feeds: [...], text: 'I love this movie!', collection_refs: ['movies:lord_of_the_rings'],});
final response = await feed.addActivity( request: const FeedAddActivityRequest( type: 'post', text: 'I love this movie!', collectionRefs: ['movies:lord_of_the_rings'], ),);
AddActivityRequest activity = AddActivityRequest.builder() .type("post") .feeds(List.of("user:jack")) .text("I love this movie!") .userID("jack") .collectionRefs(List.of("movies:lord_of_the_rings")) .build();AddActivityResponse response = feeds.addActivity(activity).execute().getData();
$activity = new GeneratedModels\AddActivityRequest( type: 'post', feeds: ['user:jack'], text: 'I love this movie!', userID: 'jack', collectionRefs: ['movies:lord_of_the_rings']);$response = $feedsClient->addActivity($activity);
var activity = new AddActivityRequest{ Type = "post", Text = "I love this movie!", UserID = "jack", Feeds = new List<string> { "user:jack" }, CollectionRefs = new List<string> { "movies:lord_of_the_rings" }};var response = await _feedsV3Client.AddActivityAsync(activity);
response = client.feeds.add_activity( type="post", feeds=["user:jack"], text="I love this movie!", user_id="jack", collection_refs=["movies:lord_of_the_rings"])
activity_request = GetStream::Generated::Models::AddActivityRequest.new( type: 'post', text: 'I love this movie!', user_id: 'jack', feeds: ['user:jack'], collection_refs: ['movies:lord_of_the_rings'])response = client.feeds.add_activity(activity_request)
When you have added collection references to your activities these will automatically be enriched with the collection data when reading feeds.
// Create a collectionlet createResponse = try await client.createCollections( request: .init( collections: [ .init( name: "movies", id: "lord_of_the_rings", custom: [ "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 ] ) ] ))// Add the reference to an activitylet feed = client.feed(group: "user", id: "jack")let activityResponse = try await feed.addActivity( request: .init( type: "post", text: "I love this movie!", collectionRefs: ["movies:lord_of_the_rings"] ))// Read the feed and see the enriched collection datatry await feed.getOrCreate()let activities = feed.state.activities// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collectionval createResponse: Result<List<CollectionData>> = client.createCollections( request = CreateCollectionsRequest( collections = listOf( CollectionRequest( name = "movies", id = "lord_of_the_rings", custom = mapOf( "title" to "Lord of the Rings", "genre" to "fantasy", "rating" to 9 ) ) ) ))// Add the reference to an activityval feed = client.feed(group = "user", id = "jack")val activityResponse: Result<ActivityData> = feed.addActivity( request = FeedAddActivityRequest( type = "post", text = "I love this movie!", collectionRefs = listOf("movies:lord_of_the_rings") ))// Read the feed and see the enriched collection datafeed.getOrCreate()val activities = feed.state.activities// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collectionawait client.createCollections({ collections: [ { name: "movies", id: "lord_of_the_rings", custom: { title: "Lord of the Rings", genre: "fantasy", rating: 9, }, }, ],});// Add the reference to an activityconst feed = client.feed("user", "jack");await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});// Read the feed and see the enriched collection dataconst response = await feed.getOrCreate({});console.log(response);/*{ "activities": [ { "type": "post", "text": "I love this movie!", "collections": { "movies:lord_of_the_rings": { "name": "movies", "id": "lord_of_the_rings", "custom": { "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 }, "user_id": "jack", "created_at": "2025-01-01T00:00:00.000Z", "updated_at": "2025-01-01T00:00:00.000Z", "status": "ok" } } } ], ...}*/
// Create a collectionawait client.createCollections({ collections: [ { name: "movies", id: "lord_of_the_rings", custom: { title: "Lord of the Rings", genre: "fantasy", rating: 9, }, }, ],});// Add the reference to an activityconst feed = client.feed("user", "jack");await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});// Read the feed and see the enriched collection dataconst response = await feed.getOrCreate({});console.log(response);/*{ "activities": [ { "type": "post", "text": "I love this movie!", "collections": { "movies:lord_of_the_rings": { "name": "movies", "id": "lord_of_the_rings", "custom": { "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 }, "user_id": "jack", "created_at": "2025-01-01T00:00:00.000Z", "updated_at": "2025-01-01T00:00:00.000Z", "status": "ok" } } } ], ...}*/
// Create a collectionawait client.createCollections({ collections: [ { name: "movies", id: "lord_of_the_rings", custom: { title: "Lord of the Rings", genre: "fantasy", rating: 9, }, }, ],});// Add the reference to an activityconst feed = client.feed("user", "jack");await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"],});// Read the feed and see the enriched collection dataconst response = await feed.getOrCreate({});console.log(response);/*{ "activities": [ { "type": "post", "text": "I love this movie!", "collections": { "movies:lord_of_the_rings": { "name": "movies", "id": "lord_of_the_rings", "custom": { "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 }, "user_id": "jack", "created_at": "2025-01-01T00:00:00.000Z", "updated_at": "2025-01-01T00:00:00.000Z", "status": "ok" } } } ], ...}*/
// Create a collectionawait client.feeds.createCollections({ collections: [ { name: "movies", id: "lord_of_the_rings", custom: { title: "Lord of the Rings", genre: "fantasy", rating: 9, }, }, ],});// Add the reference to an activityconst feed = client.feeds.feed("user", "jack");await feed.addActivity({ type: "post", text: "I love this movie!", collection_refs: ["movies:lord_of_the_rings"], user_id: "jack",});// Read the feed and see the enriched collection dataconst response = await feed.getOrCreate({ user_id: "jack" });console.log(response);/*{ "activities": [ { "type": "post", "text": "I love this movie!", "collections": { "movies:lord_of_the_rings": { "name": "movies", "id": "lord_of_the_rings", "custom": { "title": "Lord of the Rings", "genre": "fantasy", "rating": 9 }, "user_id": "jack", "created_at": "2025-01-01T00:00:00.000Z", "updated_at": "2025-01-01T00:00:00.000Z", "status": "ok" } } } ], ...}*/
// Create a collectionfinal createResponse = await client.createCollections( collections: [ const CollectionRequest( name: 'movies', id: 'lord_of_the_rings', custom: { 'title': 'Lord of the Rings', 'genre': 'fantasy', 'rating': 9, }, ), ],);// Add the reference to an activityfinal feed = client.feed(group: 'user', id: 'jack');final activityResponse = await feed.addActivity( request: const FeedAddActivityRequest( type: 'post', text: 'I love this movie!', collectionRefs: ['movies:lord_of_the_rings'], ),);// Read the feed and see the enriched collection dataawait feed.getOrCreate();final activities = feed.state.activities;// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collection_, err := client.Feeds().CreateCollections(context.Background(), &getstream.CreateCollectionsRequest{ Collections: []getstream.CollectionRequest{ { Name: "movies", ID: "lord_of_the_rings", Custom: map[string]any{ "title": "Lord of the Rings", "genre": "fantasy", "rating": 9, }, }, },})if err != nil { log.Fatal("Error creating collections:", err)}// Add the reference to an activityfeedsClient := client.Feeds()feed := feedsClient.Feed("user", "jack")_, err = feedsClient.AddActivity(context.Background(), &getstream.AddActivityRequest{ Type: "post", Feeds: []string{"user:jack"}, Text: getstream.PtrTo("I love this movie!"), UserID: getstream.PtrTo("jack"), CollectionRefs: []string{"movies:lord_of_the_rings"},})if err != nil { log.Fatal("Error adding activity:", err)}// Read the feed and see the enriched collection dataresponse, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("jack"),})if err != nil { log.Fatal("Error reading feed:", err)}activities := response.Data.Activities// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collectionMap<String, Object> customData = new HashMap<>();customData.put("title", "Lord of the Rings");customData.put("genre", "fantasy");customData.put("rating", 9);CollectionRequest collection = CollectionRequest.builder() .name("movies") .id("lord_of_the_rings") .custom(customData) .build();CreateCollectionsRequest createRequest = CreateCollectionsRequest.builder() .collections(List.of(collection)) .build();feeds.createCollections(createRequest).execute().getData();// Add the reference to an activityAddActivityRequest activity = AddActivityRequest.builder() .type("post") .feeds(List.of("user:jack")) .text("I love this movie!") .userID("jack") .collectionRefs(List.of("movies:lord_of_the_rings")) .build();feeds.addActivity(activity).execute().getData();// Read the feed and see the enriched collection dataFeed feed = new Feed("user", "jack", feeds);GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder() .userID("jack") .build();GetOrCreateFeedResponse feedResponse = feed.getOrCreate(feedRequest).getData();List<Activity> activities = feedResponse.getActivities();// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collection$collection = new GeneratedModels\CollectionRequest( name: 'movies', id: 'lord_of_the_rings', custom: (object)[ 'title' => 'Lord of the Rings', 'genre' => 'fantasy', 'rating' => 9, ]);$feedsClient->createCollections( new GeneratedModels\CreateCollectionsRequest(collections: [$collection]));// Add the reference to an activity$activity = new GeneratedModels\AddActivityRequest( type: 'post', feeds: ['user:jack'], text: 'I love this movie!', userID: 'jack', collectionRefs: ['movies:lord_of_the_rings']);$feedsClient->addActivity($activity);// Read the feed and see the enriched collection data$feed = $feedsClient->feed('user', 'jack');$response = $feed->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest(userID: 'jack'));$activities = $response->getData()->activities;// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
// Create a collectionvar collection = new CollectionRequest{ Name = "movies", ID = "lord_of_the_rings", Custom = new Dictionary<string, object> { { "title", "Lord of the Rings" }, { "genre", "fantasy" }, { "rating", 9 } }};await _feedsV3Client.CreateCollectionsAsync( new CreateCollectionsRequest { Collections = new List<CollectionRequest> { collection } });// Add the reference to an activityvar activity = new AddActivityRequest{ Type = "post", Text = "I love this movie!", UserID = "jack", Feeds = new List<string> { "user:jack" }, CollectionRefs = new List<string> { "movies:lord_of_the_rings" }};await _feedsV3Client.AddActivityAsync(activity);// Read the feed and see the enriched collection datavar feedResponse = await _feedsV3Client.GetOrCreateFeedAsync( FeedGroupID: "user", FeedID: "jack", request: new GetOrCreateFeedRequest { UserID = "jack" });var activities = feedResponse.Activities;// The activities will contain enriched collection data in the collections field// Example response structure:// {// "activities": [// {// "type": "post",// "text": "I love this movie!",// "collections": {// "movies:lord_of_the_rings": {// "name": "movies",// "id": "lord_of_the_rings",// "custom": {// "title": "Lord of the Rings",// "genre": "fantasy",// "rating": 9// },// "user_id": "jack",// "created_at": "2025-01-01T00:00:00.000Z",// "updated_at": "2025-01-01T00:00:00.000Z",// "status": "ok"// }// }// }// ],// ...// }
# Create a collectionresponse = client.feeds.create_collections( collections=[ CollectionRequest( name="movies", id="lord_of_the_rings", custom={ "title": "Lord of the Rings", "genre": "fantasy", "rating": 9, } ) ])# Add the reference to an activityresponse = client.feeds.add_activity( type="post", feeds=["user:jack"], text="I love this movie!", user_id="jack", collection_refs=["movies:lord_of_the_rings"])# Read the feed and see the enriched collection datafeed = client.feeds.feed("user", "jack")feed_response = feed.get_or_create(user_id="jack")activities = feed_response.activities# The activities will contain enriched collection data in the collections field# Example response structure:# {# "activities": [# {# "type": "post",# "text": "I love this movie!",# "collections": {# "movies:lord_of_the_rings": {# "name": "movies",# "id": "lord_of_the_rings",# "custom": {# "title": "Lord of the Rings",# "genre": "fantasy",# "rating": 9# },# "user_id": "jack",# "created_at": "2025-01-01T00:00:00.000Z",# "updated_at": "2025-01-01T00:00:00.000Z",# "status": "ok"# }# }# }# ],# ...# }
# Create a collectioncollection = GetStream::Generated::Models::CollectionRequest.new( name: 'movies', id: 'lord_of_the_rings', custom: { title: 'Lord of the Rings', genre: 'fantasy', rating: 9 })request = GetStream::Generated::Models::CreateCollectionsRequest.new( collections: [collection])client.feeds.create_collections(request)# Add the reference to an activityactivity_request = GetStream::Generated::Models::AddActivityRequest.new( type: 'post', text: 'I love this movie!', user_id: 'jack', feeds: ['user:jack'], collection_refs: ['movies:lord_of_the_rings'])client.feeds.add_activity(activity_request)# Read the feed and see the enriched collection datafeed = client.feed('user', 'jack')feed_request = GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'jack')feed_response = feed.get_or_create_feed(feed_request)activities = feed_response.activities# The activities will contain enriched collection data in the collections field# Example response structure:# {# "activities": [# {# "type": "post",# "text": "I love this movie!",# "collections": {# "movies:lord_of_the_rings": {# "name": "movies",# "id": "lord_of_the_rings",# "custom": {# "title": "Lord of the Rings",# "genre": "fantasy",# "rating": 9# },# "user_id": "jack",# "created_at": "2025-01-01T00:00:00.000Z",# "updated_at": "2025-01-01T00:00:00.000Z",# "status": "ok"# }# }# }# ],# ...# }
The enrichment is a best effort process. Missing or deleted collections will not be enriched but will be retured with a status of notfound