# Quick Start Stream lets you build **activity feeds at scale**. The largest apps on Stream have over **100 M+ users**. V3 keeps that scalability while giving you more flexibility over the content shown in your feed. ## What’s new in V3 - **For-You feed**: Most modern apps combine a “For You” feed with a regular “Following” feed. V3 introduces **activity selectors** so you can: - surface popular activities - show activities near the user - match activities to a user’s interests - mix-and-match these selectors to build an engaging personalized feed. - **Performance**: 20–30 % faster flat feeds. Major speedups for aggregation & ranking (full benchmarks coming soon) - **Client-side SDKs**: Swift/Kotlin/React/Flutter & React Native are in progress - **Activity filtering**: Filter activity feeds with almost no hit to performance - **Comments**: Voting, ranking, threading, images, URL previews, @mentions & notifications. Basically all the features of Reddit style commenting systems. - **Advanced feed features**: Activity expiration • visibility controls • feed visibility levels • feed members • bookmarking • follow-approval flow • stories support. - **Search & queries**: Activity search, **query activities**, and **query feeds** endpoints. - **Modern essentials**: Permissions • OpenAPI spec • GDPR endpoints • realtime WebSocket events • push notifications • “own capabilities” API. - **Coming soon**: User-engagement stats • Campaign API • V2 → V3 migration tools. ### What's coming for feeds V3? - Android and Flutter SDKs to extend the existing JavaScript, React, React Native and iOS SDKs ✅ - Python, Java, PHP and .NET SDKs to extend the existing Go and Node SDKs ✅ - Ruby SDK ✅ - Dashboard support (in the meantime you can use server-side SDKs for admin tasks, for example, creating feed groups) - [Beta Dashboard](https://beta.dashboard.getstream.io/) - Migration system from V2 to V3 ✅ - Benchmarking ✅ - User-engagement stats ⏳ - Campaign API ⏳ ## Server side VS Client side - Most API calls can be done client side - Client side API calls use the permission system. Server side API calls have full access Most apps will default to making API calls client side, and server side do the following: - Updating feed groups or feed views for ranking and aggregation - Syncing users - Returning tokens for authenticating users - Writing to feeds that don't belong to the current user (since the user doens't have access client side to do this) --- ## Getting Started ```ruby require 'getstream_ruby' # Initialize the client client = GetStreamRuby.manual( api_key: 'your_api_key', api_secret: 'your_api_secret' ) # Create a feed (or get its data if exists) feed_response = client.feeds.get_or_create_feed( 'user', 'john', GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john') ) # Add activity activity_request = GetStream::Generated::Models::AddActivityRequest.new( type: 'post', text: 'Hello, Stream Feeds!', user_id: 'john', feeds: ['user:john'] ) response = client.feeds.add_activity(activity_request) ``` ```swift import StreamCore import StreamFeeds // Initialize the client let client = FeedsClient( apiKey: APIKey(""), user: User(id: "john"), token: UserToken(""), tokenProvider: nil // used to refresh expiring tokens ) // Create a feed (or get its data if exists) let feed = client.feed(group: "user", id: "john") try await feed.getOrCreate() // Add activity let activity = try await feed.addActivity( request: .init( text: "Hello, Stream Feeds!", type: "post" ) ) ``` ```kotlin // Initialize the client and connect val client = FeedsClient( context = context, apiKey = StreamApiKey.fromString(""), user = User(id = "john"), tokenProvider = object : StreamTokenProvider { override suspend fun loadToken(userId: StreamUserId): StreamToken { return StreamToken.fromString("") } } ) val connectResult: Result = client.connect() // Create a feed (or get its data if it exists) val feed = client.feed(group = "user", id = "john") feed.getOrCreate() // Add an activity val result: Result = feed.addActivity( request = FeedAddActivityRequest( type = "post", text = "Hello, Stream Feeds!", ) ) ``` ```js import { FeedsClient } from "@stream-io/feeds-client"; const client = new FeedsClient(""); await client.connectUser({ id: "john" }, ""); // Create a feed (or get its data if exists) const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Add activity await feed.addActivity({ text: "Hello, Stream Feeds!", type: "post", }); ``` ```js import { FeedsClient } from "@stream-io/feeds-client"; const client = new FeedsClient(""); await client.connectUser({ id: "john" }, ""); // Create a feed (or get its data if exists) const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Add activity await feed.addActivity({ text: "Hello, Stream Feeds!", type: "post", }); ``` ```js import { FeedsClient } from "@stream-io/feeds-client"; const client = new FeedsClient(""); await client.connectUser({ id: "john" }, ""); // Create a feed (or get its data if exists) const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Add activity await feed.addActivity({ text: "Hello, Stream Feeds!", type: "post", }); ``` ```js import { StreamClient } from "@stream-io/node-sdk"; // Initialize the client const client = new StreamClient("", ""); // Create a feed (or get its data if exists) const feed = client.feeds.feed("user", "john"); await feed.getOrCreate({ user_id: "john" }); // Add activity await client.feeds.addActivity({ type: "post", feeds: ["user:john"], text: "Hello, Stream Feeds!", user_id: "john", }); ``` ```js import { FeedsClient } from "@stream-io/feeds-react-sdk"; const client = new FeedsClient(""); await client.connectUser({ id: "john" }, ""); // Create a feed (or get its data if exists) const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Add activity await feed.addActivity({ text: "Hello, Stream Feeds!", type: "post", }); ``` ```js import { FeedsClient } from "@stream-io/feeds-react-native-sdk"; const client = new FeedsClient(""); await client.connectUser({ id: "john" }, ""); // Create a feed (or get its data if exists) const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Add activity await feed.addActivity({ text: "Hello, Stream Feeds!", type: "post", }); ``` ```dart // Import the package import 'package:stream_feeds/stream_feeds.dart'; // Initialize the client final client = StreamFeedsClient( apiKey: '', user: User(id: 'john'), tokenProvider: TokenProvider.static(UserToken('')), ); await client.connect(); // Create a feed (or get its data if exists) final feed = client.feed(group: 'user', id: 'john'); final result = await feed.getOrCreate(); // Add activity final activity = await feed.addActivity( request: FeedAddActivityRequest(type: 'post', text: 'Hello, Stream Feeds!'), ); ``` ```java import io.getstream.services.framework.StreamSDKClient; import io.getstream.services.FeedsImpl; import io.getstream.services.Feed; import io.getstream.services.framework.StreamHTTPClient; import io.getstream.models.*; StreamSDKClient client = new StreamSDKClient("", ""); FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("", "")); // Create a feed (or get its data if exists) Feed feed = new Feed("user", "john", feedsClient); GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build(); feed.getOrCreate(feedRequest); // Add activity AddActivityRequest activity = AddActivityRequest.builder() .type("post") .text("Hello, Stream Feeds!") .userID("john") .build(); feedsClient.addActivity(activity).execute(); ``` ```python from getstream import Stream client = Stream(api_key="", api_secret="") # Create a feed (or get its data if exists) feed = client.feeds.feed("user", "john") feed.get_or_create(user_id="john") # Add activity response = client.feeds.add_activity( type="post", feeds=[feed.get_feed_identifier()], text="Hello, Stream Feeds!", user_id="john" ) ``` ```csharp using GetStream; using GetStream.Models; // Initialize client var builder = new ClientBuilder() .ApiKey("your_api_key") .ApiSecret("your_api_secret"); var client = builder.Build(); var feedsClient = builder.BuildFeedsClient(); // Create a feed (or get its data if exists) await feedsClient.GetOrCreateFeedAsync( "user", "john", new GetOrCreateFeedRequest { UserID = "john", Watch = true } ); // Add activity await feedsClient.AddActivityAsync(new AddActivityRequest { Text = "Hello, Stream Feeds!", Type = "post", UserID = "john", Feeds = new List { "user:john" } }); ``` ```go import ( "context" "log" "github.com/GetStream/getstream-go/v3" ) client, err := getstream.NewClient("api_key", "api_secret") if err != nil { log.Fatal(err) } feedsClient := client.Feeds() feed := feedsClient.Feed("user", "john") // Get or create the feed feedResponse, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error getting/creating feed:", err) } log.Printf("Response: %+v\n", feedResponse) // Add activity to the specific feed response, err := feedsClient.AddActivity(context.Background(), &getstream.AddActivityRequest{ Feeds: []string{feedResponse.Data.Feed.Feed}, Type: "post", Text: getstream.PtrTo("Hello, Stream Feeds!"), UserID: getstream.PtrTo("john"), }) log.Printf("Response: %+v\n", response) ``` ```php use GetStream\ClientBuilder; use GetStream\GeneratedModels; $feedsClient = (new ClientBuilder()) ->apiKey($apiKey) ->apiSecret($apiSecret) ->buildFeedsClient(); // Create a feed (or get its data if exists) $feed = $feedsClient->feed("user", "john"); $feed->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest(userID: "john") ); // Add activity $response = $feedsClient->addActivity(new GeneratedModels\AddActivityRequest( type: 'post', feeds: ['user:john'], text: 'Hello, Stream Feeds!', userID: 'john' )); ``` ## Key Concepts ### Activities Activities are the core content units in Stream Feeds. They can represent posts, photos, videos, polls, and any custom content type you define. ### Feeds Feeds are collections of activities. They can be personal feeds, timeline feeds, notification feeds, or custom feeds for your specific use case. ### Real-time Updates Stream Feeds provides real-time updates through WebSocket connections, ensuring your app stays synchronized with the latest content. ### Social Features Built-in support for reactions, comments, bookmarks, and polls makes it easy to build engaging social experiences. ## Common Use Cases ### Social Media Feed ```swift // Create a timeline feed let timeline = client.feed(group: "timeline", id: "john") try await timeline.getOrCreate() // Add a reaction to activity _ = try await timeline.addReaction( activityId: "activity_123", request: .init(type: "like") ) // Add a comment to activity _ = try await timeline.addComment( request: .init( comment: "Great post!", objectId: "activity_123", objectType: "activity" ) ) // Add a reaction to comment let activity = client.activity(for: "activity_123", in: FeedId(group: "timeline", id: "john")) try await activity.addCommentReaction( commentId: "comment_123", request: .init(type: "love") ) ``` ```kotlin val timeline = client.feed(group = "timeline", id = "john") timeline.getOrCreate() // Add a reaction to an activity val addReactionResult: Result = timeline.addActivityReaction( activityId = "activity_123", request = AddReactionRequest(type = "like") ) // Add a comment to an activity val addCommentResult: Result = timeline.addComment( request = ActivityAddCommentRequest( comment = "Great post!", activityId = "activity_123", ) ) // Add a reaction to a comment val addCommentReactionResult: Result = timeline.addCommentReaction( commentId = "comment_456", request = AddCommentReactionRequest(type = "like") ) ``` ```js // Create a timeline feed const timeline = client.feed("timeline", "john"); await timeline.getOrCreate(); // Add a reaction to activity await client.addReaction({ activity_id: "activity_123", type: "like", }); // Add a comment to activity await client.addComment({ object_id: "activity_123", object_type: "activity", comment: "Great post!", }); // Add a reaction to comment await client.addCommentReaction({ id: "comment_123", type: "love", }); ``` ```js // Create a timeline feed const timeline = client.feed("timeline", "john"); await timeline.getOrCreate(); // Add a reaction to activity await client.addReaction({ activity_id: "activity_123", type: "like", }); // Add a comment to activity await client.addComment({ object_id: "activity_123", object_type: "activity", comment: "Great post!", }); // Add a reaction to comment await client.addCommentReaction({ id: "comment_123", type: "love", }); ``` ```js // Create a timeline feed const timeline = client.feed("timeline", "john"); await timeline.getOrCreate(); // Add a reaction to activity await client.addReaction({ activity_id: "activity_123", type: "like", }); // Add a comment to activity await client.addComment({ object_id: "activity_123", object_type: "activity", comment: "Great post!", }); // Add a reaction to comment await client.addCommentReaction({ id: "comment_123", type: "love", }); ``` ```dart // Create a timeline feed final timeline = client.feed(group: 'timeline', id: 'john'); await timeline.getOrCreate(); // Add a reaction to activity await timeline.addActivityReaction( activityId: 'activity_123', request: AddReactionRequest(type: 'like'), ); // Add a comment to activity await timeline.addComment( request: ActivityAddCommentRequest( comment: 'Great post!', activityId: 'activity_123', ), ); // Add a reaction to comment final activity = client.activity( activityId: 'activity_123', fid: FeedId(group: 'timeline', id: 'john'), ); await activity.addCommentReaction( commentId: 'commentId', request: AddCommentReactionRequest(type: 'like'), ); ``` ```java import io.getstream.services.framework.StreamSDKClient; import io.getstream.services.FeedsImpl; import io.getstream.services.Feed; import io.getstream.services.framework.StreamHTTPClient; import io.getstream.models.*; StreamSDKClient client = new StreamSDKClient("", ""); FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("", "")); // Create a feed (or get its data if exists) Feed feed = new Feed("user", "john", feedsClient); GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build(); feed.getOrCreate(feedRequest); // Add activity AddActivityRequest activity = AddActivityRequest.builder() .type("post") .text("Hello, Stream Feeds!") .userID("john") .build(); feedsClient.addActivity(activity).execute(); // Please refer to the JavaScript examples above for the API structure ``` ```js // Create a timeline feed const timeline = client.feeds.feed("timeline", "john"); await timeline.getOrCreate({ user_id: "john" }); // Add a reaction to activity await client.feeds.addActivityReaction({ activity_id: "activity_123", type: "like", user_id: "john", }); // Add a comment to activity await client.feeds.addComment({ object_id: "activity_123", object_type: "activity", comment: "Great post!", user_id: "john", }); // Add a reaction to comment await client.feeds.addCommentReaction({ id: "comment_456", type: "love", user_id: "john", }); ``` ```python from getstream import Stream client = Stream(api_key="", api_secret="") # Create a feed (or get its data if exists) feed = client.feeds.feed("user", "john") feed.get_or_create(user_id="john") # Add activity response = client.feeds.add_activity( type="post", feeds=[feed.get_feed_identifier()], text="Hello, Stream Feeds!", user_id="john" ) ``` ```csharp // Create a timeline feed await feedsClient.GetOrCreateFeedAsync( "timeline", "john", new GetOrCreateFeedRequest { UserID = "john" } ); // Add a comment to activity await feedsClient.AddCommentAsync(new AddCommentRequest { Comment = "Great post!", ObjectID = "activity_123", ObjectType = "activity", UserID = "john" }); // Add a reaction to comment await feedsClient.AddCommentReactionAsync( "comment_123", new AddCommentReactionRequest { Type = "love", UserID = "john" } ); ``` ```go feedsClient := client.Feeds() // Create timeline feed timeline := feedsClient.Feed("timeline", "john") _, err = timeline.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error getting/creating feed:", err) } // Add a reaction to activity addReactionResponse, err := feedsClient.AddReaction(context.Background(), "activity_123", &getstream.AddReactionRequest{ Type: "like", UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal(err) } log.Printf("Response: %+v\n", addReactionResponse) // Add comment to activity addCommentResponse, err := feedsClient.AddComment(context.Background(), &getstream.AddCommentRequest{ Comment: "Great post!", ObjectID: "activity_123", ObjectType: "activity", UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal(err) } log.Printf("Response: %+v\n", addCommentResponse) // Add a reaction to comment addCommentReactionResponse, err := feedsClient.AddCommentReaction(context.Background(), addCommentResponse.Data.Comment.ID, &getstream.AddCommentReactionRequest{ Type: "love", UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal(err) } log.Printf("Response: %+v\n", addCommentReactionResponse) ``` ```php $feedsClient = (new ClientBuilder()) ->apiKey($apiKey) ->apiSecret($apiSecret) ->buildFeedsClient(); // Create timeline feed $timeline = $feedsClient->feed("timeline", "john"); $response = $timeline->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest(userID: "john") ); // Add a reaction to activity $reactionResponse = $feedsClient->addActivityReaction( "activity_123", new GeneratedModels\AddReactionRequest( type: "like", userID: "john" ) ); // Add a comment to activity $commentResponse = $feedsClient->addComment( new GeneratedModels\AddCommentRequest( objectID: "activity_123", objectType: 'activity', comment: 'Great post!', userID: 'john' ) ); // Add a reaction to comment $commentReactionResponse = $feedsClient->addCommentReaction( $commentResponse->getData()->comment->id, new GeneratedModels\AddCommentReactionRequest( type: "love", userID: "john" ) ); ``` ```ruby # Create a timeline feed timeline_response = client.feeds.get_or_create_feed( 'timeline', 'john', GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john') ) # Add a reaction to activity reaction_request = GetStream::Generated::Models::AddReactionRequest.new( type: 'like', user_id: 'john' ) reaction_response = client.feeds.add_reaction('activity_123', reaction_request) # Add a comment to activity comment_request = GetStream::Generated::Models::AddCommentRequest.new( comment: 'Great post!', object_id: 'activity_123', object_type: 'activity', user_id: 'john' ) comment_response = client.feeds.add_comment(comment_request) # Add a reaction to comment comment_reaction_request = GetStream::Generated::Models::AddCommentReactionRequest.new( type: 'love', user_id: 'john' ) comment_reaction_response = client.feeds.add_comment_reaction( comment_response.comment.id, comment_reaction_request ) ``` ### Notification Feed ```swift // Create a notification feed let notifications = client.feed(group: "notification", id: "john") try await notifications.getOrCreate() // Mark notifications as read try await notifications.markActivity(request: .init(markAllRead: true)) ``` ```kotlin // Create a notification feed val notifications = client.feed(group = "notification", id = "john") notifications.getOrCreate() // Mark notifications as read notifications.markActivity( request = MarkActivityRequest(markAllRead = true) ) ``` ```js // Create a notification feed const notifications = client.feed("notification", "john"); await notifications.getOrCreate(); // Mark notifications as read await notifications.markActivity({ mark_all_read: true, }); ``` ```js // Create a notification feed const notifications = client.feed("notification", "john"); await notifications.getOrCreate(); // Mark notifications as read await notifications.markActivity({ mark_all_read: true, }); ``` ```js // Create a notification feed const notifications = client.feed("notification", "john"); await notifications.getOrCreate(); // Mark notifications as read await notifications.markActivity({ mark_all_read: true, }); ``` ```dart // Create a notification feed final notifications = client.feed(group: 'notification', id: 'john'); await notifications.getOrCreate(); // Mark notifications as read await notifications.markActivity( request: MarkActivityRequest(markAllRead: true), ); ``` ```java import io.getstream.services.framework.StreamSDKClient; import io.getstream.services.FeedsImpl; import io.getstream.services.Feed; import io.getstream.services.framework.StreamHTTPClient; import io.getstream.models.*; StreamSDKClient client = new StreamSDKClient("", ""); FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("", "")); // Create a notification feed Feed notifications = new Feed("notification", "john", feedsClient); GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build(); notifications.getOrCreate(feedRequest); ``` ```csharp // Create a notification feed await feedsClient.GetOrCreateFeedAsync( "notification", "john", new GetOrCreateFeedRequest { UserID = "john" } ); // Mark notifications as read await feedsClient.MarkActivityAsync( "notification", "john", new MarkActivityRequest { MarkAllRead = true } ); ``` ```php // Create a notification feed $notifications = $feedsClient->feed("notification", "john"); $notifications->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest(userID: "john") ); // Mark notifications as read $markResponse = $notifications->markActivity( new GeneratedModels\MarkActivityRequest(markAllRead: true, userID: "john") ); ``` ```go feedsClient := client.Feeds() // Create a notification feed feedResponse, err := feedsClient.GetOrCreateFeed(context.Background(), "notification", "john", &getstream.GetOrCreateFeedRequest{ UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal(err) } log.Printf("Response: %+v\n", feedResponse) ``` ```ruby # Create a notification feed notifications_response = client.feeds.get_or_create_feed( 'notification', 'john', GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john') ) # Mark notifications as read mark_request = GetStream::Generated::Models::MarkActivityRequest.new( mark_all_read: true ) client.feeds.mark_activity('notification', 'john', mark_request) ``` ```js // Create a notification feed const notifications = client.feeds.feed("notification", "john"); await notifications.getOrCreate({ user_id: "john" }); // Mark notifications as read await notifications.markActivity({ mark_all_read: true, user_id: "john", }); ``` ### Polls ```swift // Create a poll let feedId = FeedId(group: "user", id: "john") let feed = client.feed(for: feedId) let activityData = try await feed.createPoll( request: .init( name: "What's your favorite color?", options: [ PollOptionInput(text: "Red"), PollOptionInput(text: "Blue"), PollOptionInput(text: "Green") ] ), activityType: "poll" ) // Vote on a poll let activity = client.activity(for: activityData.id, in: feedId) _ = try await activity.castPollVote( request: .init( vote: .init( optionId: "option_456" ) ) ) ``` ```kotlin // Create a poll val feedId = FeedId(group = "user", id = "john") val feed = client.feed(fid = feedId) val request = CreatePollRequest( name = "What's your favorite color?", options = listOf( PollOptionInput(text = "Red"), PollOptionInput(text = "Blue"), PollOptionInput(text = "Green") ) ) val activityData: Result = feed.createPoll( request = request, activityType = "poll" ) // Vote on a poll val activity = client.activity( activityId = activityData.getOrNull()?.id ?: "", fid = feedId ) val pollVoteData: Result = activity.castPollVote( request = CastPollVoteRequest( vote = VoteData(optionId = "option_456") ) ) ``` ```js // Create a poll const feed = client.feed("user", "john"); const poll = await client.createPoll({ name: "What is your favorite color?", options: [{ text: "Red" }, { text: "Blue" }, { text: "Green" }], }); // Attach it to an activity const activity = await feed.addActivity({ text: "What is your favorite color?", type: "poll", poll_id: poll.poll.id, }); // Vote await client.castPollVote({ poll_id: poll.poll.id, activity_id: activity.activity.id, vote: { option_id: poll.poll.options[0].id, }, }); ``` ```js // Create a poll const feed = client.feed("user", "john"); const poll = await client.createPoll({ name: "What is your favorite color?", options: [{ text: "Red" }, { text: "Blue" }, { text: "Green" }], }); // Attach it to an activity const activity = await feed.addActivity({ text: "What is your favorite color?", type: "poll", poll_id: poll.poll.id, }); // Vote await client.castPollVote({ poll_id: poll.poll.id, activity_id: activity.activity.id, vote: { option_id: poll.poll.options[0].id, }, }); ``` ```js // Create a poll const feed = client.feed("user", "john"); const poll = await client.createPoll({ name: "What is your favorite color?", options: [{ text: "Red" }, { text: "Blue" }, { text: "Green" }], }); // Attach it to an activity const activity = await feed.addActivity({ text: "What is your favorite color?", type: "poll", poll_id: poll.poll.id, }); // Vote await client.castPollVote({ poll_id: poll.poll.id, activity_id: activity.activity.id, vote: { option_id: poll.poll.options[0].id, }, }); ``` ```dart // Create a poll final feedId = FeedId(group: 'timeline', id: 'john'); final feed = client.feedFromId(feedId); final result = await feed.createPoll( request: CreatePollRequest( name: "What's your favorite color?", options: const [ PollOptionInput(text: 'Red'), PollOptionInput(text: 'Blue'), PollOptionInput(text: 'Green'), ], ), activityType: 'poll', ); // Vote on a poll final activityData = result.getOrThrow(); final activity = client.activity(activityId: activityData.id, fid: feedId); await activity.castPollVote( CastPollVoteRequest(vote: VoteData(optionId: 'option_456')), ); ``` ```java import io.getstream.services.framework.StreamSDKClient; import io.getstream.services.FeedsImpl; import io.getstream.services.Feed; import io.getstream.services.framework.StreamHTTPClient; import io.getstream.models.*; StreamSDKClient client = new StreamSDKClient("", ""); FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("", "")); // Create a feed (or get its data if exists) Feed feed = new Feed("user", "john", feedsClient); GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build(); feed.getOrCreate(feedRequest); // Add activity AddActivityRequest activity = AddActivityRequest.builder() .type("post") .text("Hello, Stream Feeds!") .userID("john") .build(); feedsClient.addActivity(activity).execute(); // Please refer to the JavaScript examples above for the API structure ``` ```python from getstream import Stream client = Stream(api_key="", api_secret="") # Create a feed (or get its data if exists) feed = client.feeds.feed("user", "john") feed.get_or_create(user_id="john") # Note: Python SDK doesn't have built-in poll creation methods # You would need to implement poll creation using custom activities ``` ```php $feedsClient = (new ClientBuilder()) ->apiKey($apiKey) ->apiSecret($apiSecret) ->buildFeedsClient(); $client = (new ClientBuilder()) ->apiKey($apiKey) ->apiSecret($apiSecret) ->build(); // Create a poll $poll = new GeneratedModels\CreatePollRequest( name: 'What is your favorite color?', userID: 'john', options: [ new GeneratedModels\PollOptionInput("Red"), new GeneratedModels\PollOptionInput("Blue"), new GeneratedModels\PollOptionInput("Green"), ] ); $pollResponse = $client->createPoll($poll); $pollData = $pollResponse->getData(); $pollId = $pollData->poll->id; // Create activity with the poll $pollActivity = new GeneratedModels\AddActivityRequest( type: 'poll', feeds: ['user:john'], pollID: $pollId, text: 'What is your favorite color?', userID: 'john' ); $response = $feedsClient->addActivity($pollActivity); // Vote on the poll $activityData = $response->getData(); $activityId = $activityData->activity->id; $optionId = $pollData->poll->options[0]->id; $voteResponse = $feedsClient->castPollVote($activityId, $pollId, new GeneratedModels\CastPollVoteRequest( vote: new GeneratedModels\VoteData(optionID: $optionId), userID: "john" ) ); ``` ```go // Create a poll pollResponse, err := client.CreatePoll(context.Background(), &getstream.CreatePollRequest{ Name: "What's your favorite Go feature?", Options: []getstream.PollOptionInput{ {Text: getstream.PtrTo("Goroutines")}, {Text: getstream.PtrTo("Channels")}, {Text: getstream.PtrTo("Interfaces")}, }, UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error creating poll:", err) } log.Printf("Poll Response: %+v\n", pollResponse) // Add activity with poll feedsClient := client.Feeds() pollActivity, err := feedsClient.AddActivity(context.Background(), &getstream.AddActivityRequest{ Feeds: []string{"user:john"}, Text: getstream.PtrTo("Check out this poll!"), Type: "post", UserID: getstream.PtrTo("john"), PollID: getstream.PtrTo(pollResponse.Data.Poll.ID), }) if err != nil { log.Fatal("Error adding activity:", err) } log.Printf("Response: %+v\n", pollActivity) // Cast a vote on a poll voteResponse, err := feedsClient.CastPollVote(context.Background(), pollActivity.Data.Activity.ID, pollResponse.Data.Poll.ID, &getstream.CastPollVoteRequest{ Vote: &getstream.VoteData{ OptionID: getstream.PtrTo(pollResponse.Data.Poll.Options[0].ID), }, UserID: getstream.PtrTo("john"), }) if err != nil { log.Fatal("Error casting vote:", err) } log.Printf("Response: %+v\n", voteResponse) ``` ```csharp // Cast a vote on an existing poll await feedsClient.CastPollVoteAsync( "activity_id", // The activity ID containing the poll "poll_id", // The poll ID new CastPollVoteRequest { Vote = new VoteData { OptionID = "option_id" }, UserID = "john" } ); ``` ```ruby # Note: Poll creation is not yet supported in Ruby SDK v0.1.5 # You can only vote on existing polls # Assuming a poll already exists with activity_id and poll_id # Cast a vote on an existing poll vote_request = GetStream::Generated::Models::CastPollVoteRequest.new( vote: GetStream::Generated::Models::VoteData.new( option_id: 'option_id_here' # ID of the poll option to vote for ), user_id: 'john' ) # Vote on the poll vote_response = client.feeds.cast_poll_vote( 'activity_id', # The activity ID containing the poll 'poll_id', # The poll ID vote_request ) ``` ```js const poll = await client.createPoll({ name: "What is your favorite color?", options: [{ text: "Red" }, { text: "Blue" }, { text: "Green" }], user_id: "john", }); // Attach it to an activity const activity = await client.feeds.addActivity({ feeds: ["user:john"], text: "What is your favorite color?", type: "poll", poll_id: poll.poll.id, user_id: "john", }); // Cast a vote on an existing poll await client.feeds.castPollVote({ activity_id: "activity_123", poll_id: "poll_456", user_id: "john", vote: { option_id: "option_789", }, }); ``` ## Advanced Features ### Custom Activity Types Create custom activity types to represent your app's specific content: ```swift let workoutActivity = try await feed.addActivity( request: .init( custom: [ "distance": 5.2, "duration": 1800, "calories": 450 ], text: "Just finished my run", type: "workout" ) ) ``` ```kotlin val workoutActivity: Result = feed.addActivity( request = FeedAddActivityRequest( custom = mapOf( "distance" to 5.2, "duration" to 1800, "calories" to 450 ), text = "Just finished my run", type = "workout" ) ) ``` ```js const feed = client.feed("user", "john"); await feed.addActivity({ type: "workout", text: "Just finished my run", custom: { distance: 5.2, duration: 1800, calories: 450, }, }); ``` ```js const feed = client.feed("user", "john"); await feed.addActivity({ type: "workout", text: "Just finished my run", custom: { distance: 5.2, duration: 1800, calories: 450, }, }); ``` ```js const feed = client.feed("user", "john"); await feed.addActivity({ type: "workout", text: "Just finished my run", custom: { distance: 5.2, duration: 1800, calories: 450, }, }); ``` ```dart final workoutActivity = await feed.addActivity( request: FeedAddActivityRequest( text: 'Just finished my run', custom: {'distance': 5.2, 'duration': 1800, 'calories': 450}, type: 'workout', ), ); ``` ```java import io.getstream.services.framework.StreamSDKClient; import io.getstream.services.FeedsImpl; import io.getstream.services.Feed; import io.getstream.services.framework.StreamHTTPClient; import io.getstream.models.*; StreamSDKClient client = new StreamSDKClient("", ""); FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("", "")); // Create a feed (or get its data if exists) Feed feed = new Feed("user", "john", feedsClient); GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build(); feed.getOrCreate(feedRequest); // Add activity AddActivityRequest activity = AddActivityRequest.builder() .type("post") .text("Hello, Stream Feeds!") .userID("john") .build(); feedsClient.addActivity(activity).execute(); // Please refer to the JavaScript examples above for the API structure ``` ```python from getstream import Stream client = Stream(api_key="", api_secret="") # Create a feed (or get its data if exists) feed = client.feeds.feed("user", "john") feed.get_or_create(user_id="john") # Add custom activity response = client.feeds.add_activity( type="workout", feeds=[feed.get_feed_identifier()], text="Just finished my run", user_id="john", custom={ "distance": 5.2, "duration": 1800, "calories": 450 } ) ``` ```go // Add custom activity feedsClient := client.Feeds() response, err := feedsClient.AddActivity(context.Background(), &getstream.AddActivityRequest{ Type: "workout", Feeds: []string{"user:john"}, Text: getstream.PtrTo("Just finished my run"), UserID: getstream.PtrTo("john"), Custom: map[string]any{ "distance": 5.2, "duration": 1800, "calories": 450, }, }) if err != nil { log.Fatal("Error adding activity:", err) } log.Printf("Response: %+v\n", response) ``` ```php // Create a feed (or get its data if exists) $feed = $feedsClient->feed("user", "john"); $feed->getOrCreateFeed( new GeneratedModels\GetOrCreateFeedRequest(userID: "john") ); // Add custom activity $feedsClient->addActivity( new GeneratedModels\AddActivityRequest( type: "workout", text: "Just finished my run", userID: "john", feeds: ["user:john"], custom: (object)[ "distance" => 5.2, "duration" => 1800, "calories" => 450, ], ) ); ``` ```csharp // Add custom activity with custom fields await feedsClient.AddActivityAsync(new AddActivityRequest { Type = "workout", Text = "Just finished my run", UserID = "john", Feeds = new List { "user:john" }, Custom = new Dictionary { { "distance", 5.2 }, { "duration", 1800 }, { "calories", 450 } } }); ``` ```ruby # Add custom activity with custom fields workout_activity = GetStream::Generated::Models::AddActivityRequest.new( type: 'workout', text: 'Just finished my run', user_id: 'john', feeds: ['user:john'], custom: { distance: 5.2, duration: 1800, calories: 450 } ) response = client.feeds.add_activity(workout_activity) ``` ```js // Add custom activity with custom fields await client.feeds.addActivity({ type: "workout", feeds: ["user:john"], text: "Just finished my run", user_id: "john", custom: { distance: 5.2, duration: 1800, calories: 450, }, }); ``` ### Real-time Updates with State Layer Only for client-side SDKs ```swift @MainActor class FeedViewModel: ObservableObject { private var cancellables = Set() private let feed: Feed @Published var activities: [ActivityData] = [] init(feed: Feed) { self.feed = feed setupRealtimeUpdates() } private func setupRealtimeUpdates() { feed.state.$activities .sink { [weak self] activities in self?.activities = activities } .store(in: &cancellables) } } ``` ```kotlin class FeedViewModel(private val feed: Feed) : ViewModel() { val activities: StateFlow> = feed.state.activities init { setupRealtimeUpdates() } private fun setupRealtimeUpdates() { viewModelScope.launch { val result: Result = feed.getOrCreate() // handle result } } } ``` ```js const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); feed.state.subscribe((state) => { // Called everytime the state changes console.log(state); }); // or if you only want to observe part of the state feed.state.subscribeWithSelector( (state) => ({ activities: state.activities, }), (state, prevState) => { console.log(state.activities, prevState?.activities); }, ); // Current state console.log(feed.state.getLatestValue()); ``` ```js const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Read state reactively with hooks const { activities } = useFeedActivities(feed) ?? {}; ``` ```js const feed = client.feed("user", "john"); // Subscribe to WebSocket events for state updates await feed.getOrCreate({ watch: true }); // Read state reactively with hooks const { activities } = useFeedActivities(feed) ?? {}; ``` ```dart import 'package:flutter/widgets.dart'; import 'package:flutter_state_notifier/flutter_state_notifier.dart'; import 'package:stream_feeds/stream_feeds.dart'; class FeedView extends StatefulWidget { const FeedView({super.key, required this.feed}); final Feed feed; @override State createState() => _FeedViewState(); } class _FeedViewState extends State { @override void initState() { super.initState(); widget.feed.getOrCreate(); } @override void dispose() { widget.feed.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return StateNotifierBuilder( stateNotifier: widget.feed.notifier, builder: (BuildContext context, FeedState state, Widget? child) { return Text(state.feed?.name ?? ''); }, ); } } ``` --- This page was last updated at 2026-03-20T20:32:07.645Z. For the most recent version of this documentation, visit [https://getstream.io/activity-feeds/docs/javascript/](https://getstream.io/activity-feeds/docs/javascript/).