# 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

<codetabs>

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

```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)
```

</codetabs-item>

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

```swift
import StreamCore
import StreamFeeds

// Initialize the client
let client = FeedsClient(
    apiKey: APIKey("<your_api_key>"),
    user: User(id: "john"),
    token: UserToken("<user_token>"),
    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"
    )
)
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Initialize the client and connect
val client = FeedsClient(
    context = context,
    apiKey = StreamApiKey.fromString("<your_api_key>"),
    user = User(id = "john"),
    tokenProvider = object : StreamTokenProvider {
        override suspend fun loadToken(userId: StreamUserId): StreamToken {
            return StreamToken.fromString("<user_token>")
        }
    }
)
val connectResult: Result<StreamConnectedUser> = 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<ActivityData> = feed.addActivity(
    request = FeedAddActivityRequest(
        type = "post",
        text = "Hello, Stream Feeds!",
    )
)
```

</codetabs-item>

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

```js
import { FeedsClient } from "@stream-io/feeds-client";

const client = new FeedsClient("<API key>");
await client.connectUser({ id: "john" }, "<user token>");

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

</codetabs-item>

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

```js
import { FeedsClient } from "@stream-io/feeds-client";

const client = new FeedsClient("<API key>");
await client.connectUser({ id: "john" }, "<user token>");

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

</codetabs-item>

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

```js
import { FeedsClient } from "@stream-io/feeds-client";

const client = new FeedsClient("<API key>");
await client.connectUser({ id: "john" }, "<user token>");

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

</codetabs-item>

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

```js
import { StreamClient } from "@stream-io/node-sdk";

// Initialize the client
const client = new StreamClient("<API key>", "<API secret>");

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

</codetabs-item>

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

```js
import { FeedsClient } from "@stream-io/feeds-react-sdk";

const client = new FeedsClient("<API key>");
await client.connectUser({ id: "john" }, "<user token>");

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

</codetabs-item>

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

```js
import { FeedsClient } from "@stream-io/feeds-react-native-sdk";

const client = new FeedsClient("<API key>");
await client.connectUser({ id: "john" }, "<user token>");

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

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Import the package
import 'package:stream_feeds/stream_feeds.dart';

// Initialize the client
final client = StreamFeedsClient(
  apiKey: '<your_api_key>',
  user: User(id: 'john'),
  tokenProvider: TokenProvider.static(UserToken('<user_token>')),
);
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!'),
);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```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("<API key>", "<API secret>");
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

// 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();
```

</codetabs-item>

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

```python
from getstream import Stream

client = Stream(api_key="<API key>", api_secret="<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"
)
```

</codetabs-item>

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

```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<string> { "user:john" }
});
```

</codetabs-item>

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

```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)
```

</codetabs-item>

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

```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'
));
```

</codetabs-item>

</codetabs>

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

<codetabs>

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

```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")
)
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val timeline = client.feed(group = "timeline", id = "john")
timeline.getOrCreate()

// Add a reaction to an activity
val addReactionResult: Result<FeedsReactionData> = timeline.addActivityReaction(
    activityId = "activity_123",
    request = AddReactionRequest(type = "like")
)

// Add a comment to an activity
val addCommentResult: Result<CommentData> = timeline.addComment(
    request = ActivityAddCommentRequest(
        comment = "Great post!",
        activityId = "activity_123",
    )
)

// Add a reaction to a comment
val addCommentReactionResult: Result<FeedsReactionData> = timeline.addCommentReaction(
    commentId = "comment_456",
    request = AddCommentReactionRequest(type = "like")
)
```

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```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'),
);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```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("<API key>", "<API secret>");
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

// 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
```

</codetabs-item>

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

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

</codetabs-item>

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

```python
from getstream import Stream

client = Stream(api_key="<API key>", api_secret="<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"
)
```

</codetabs-item>

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

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

</codetabs-item>

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

```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)
```

</codetabs-item>

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

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

</codetabs-item>

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

```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
)
```

</codetabs-item>

</codetabs>

### Notification Feed

<codetabs>

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

```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))
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```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)
)
```

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

<codetabs-item value="dart" label="Dart">

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

</codetabs-item>

<codetabs-item value="java" label="Java">

```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("<API key>", "<API secret>");
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

// Create a notification feed
Feed notifications = new Feed("notification", "john", feedsClient);
GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder().userID("john").build();
notifications.getOrCreate(feedRequest);
```

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

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

```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)
```

</codetabs-item>

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

```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)
```

</codetabs-item>

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

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

</codetabs-item>

</codetabs>

### Polls

<codetabs>

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

```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"
        )
    )
)
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```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<ActivityData> = feed.createPoll(
    request = request,
    activityType = "poll"
)

// Vote on a poll
val activity = client.activity(
    activityId = activityData.getOrNull()?.id ?: "",
    fid = feedId
)
val pollVoteData: Result<PollVoteData?> = activity.castPollVote(
    request = CastPollVoteRequest(
        vote = VoteData(optionId = "option_456")
    )
)
```

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```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')),
);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```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("<API key>", "<API secret>");
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

// 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
```

</codetabs-item>

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

```python
from getstream import Stream

client = Stream(api_key="<API key>", api_secret="<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
```

</codetabs-item>

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

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

</codetabs-item>

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

```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)
```

</codetabs-item>

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

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

</codetabs-item>

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

```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
)
```

</codetabs-item>

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

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

</codetabs-item>

</codetabs>

## Advanced Features

### Custom Activity Types

Create custom activity types to represent your app's specific content:

<codetabs>

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

```swift
let workoutActivity = try await feed.addActivity(
    request: .init(
        custom: [
            "distance": 5.2,
            "duration": 1800,
            "calories": 450
        ],
        text: "Just finished my run",
        type: "workout"
    )
)
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val workoutActivity: Result<ActivityData> = feed.addActivity(
    request = FeedAddActivityRequest(
        custom = mapOf(
            "distance" to 5.2,
            "duration" to 1800,
            "calories" to 450
        ),
        text = "Just finished my run",
        type = "workout"
    )
)
```

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

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

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

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final workoutActivity = await feed.addActivity(
  request: FeedAddActivityRequest(
    text: 'Just finished my run',
    custom: {'distance': 5.2, 'duration': 1800, 'calories': 450},
    type: 'workout',
  ),
);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```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("<API key>", "<API secret>");
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));

// 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
```

</codetabs-item>

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

```python
from getstream import Stream

client = Stream(api_key="<API key>", api_secret="<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
    }
)
```

</codetabs-item>

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

```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)
```

</codetabs-item>

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

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

</codetabs-item>

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

```csharp
// Add custom activity with custom fields
await feedsClient.AddActivityAsync(new AddActivityRequest
{
    Type = "workout",
    Text = "Just finished my run",
    UserID = "john",
    Feeds = new List<string> { "user:john" },
    Custom = new Dictionary<string, object>
    {
        { "distance", 5.2 },
        { "duration", 1800 },
        { "calories", 450 }
    }
});
```

</codetabs-item>

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

```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)
```

</codetabs-item>

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

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

</codetabs-item>

</codetabs>

### Real-time Updates with State Layer

Only for client-side SDKs

<codetabs>

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

```swift
@MainActor class FeedViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()
    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)
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
class FeedViewModel(private val feed: Feed) : ViewModel() {
    val activities: StateFlow<List<ActivityData>> = feed.state.activities

    init {
        setupRealtimeUpdates()
    }

    private fun setupRealtimeUpdates() {
        viewModelScope.launch {
            val result: Result<FeedData> = feed.getOrCreate()
            // handle result
        }
    }
}
```

</codetabs-item>

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

```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());
```

</codetabs-item>

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

```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) ?? {};
```

</codetabs-item>

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

```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) ?? {};
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```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<FeedView> createState() => _FeedViewState();
}

class _FeedViewState extends State<FeedView> {
  @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 ?? '');
      },
    );
  }
}
```

</codetabs-item>

</codetabs>


---

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

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