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

## Feeds V3 roadmap

Feeds V3 comes with amazing new features, however it's not yet ready for production usage. It's currently under heavy development with occasional breaking chages. If you plan to go live after end of September, we recommend Feeds V3. Otherwise, Feeds V2 is the safer choice for now.

### What's coming for feeds V3?

- Android and Flutter SDKs to extend the existing JavaScript, React, React Native and iOS SDKs
- Python, PHP, Java and .NET SDKs to extend the existing Go and Node SDKs
- Dashboard support (in the meantime you can use server-side SDKs for admin tasks, for example, creating feed groups)
- Migration system from V2 to V3
- Benchmarking

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

---

## Stream application

If you don't have a Stream account already you can create one in our dashboard and [start coding for free](https://getstream.io/try-for-free/).

To explore the feeds API create a new application in the [Stream Dashboard](https://dashboard.getstream.io/) and select **US Ohio** for data storage location.

The API is accessible worldwide, but while in alpha, data storage is only available in US Ohio. Once Feeds v3 is ready for production usage, data storage will be available through the entire **Stream global infrastructure**.

![Settings for creating a Feeds application in Stream Dashboard](../_assets/create-app.png)

To install one of the available SDKs, check out the **Installation** page of the selected technology.

Ready to try it out? Jump into the **quick-start** next to see how the API works.

## Getting Started

<!-- TODO: update link to existing document -->
<!-- If you're new to Stream Feeds, start with the [Introduction](01-introduction.md) to get up and running quickly. -->

<codetabs>

<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="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-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="go-golang" label="Go">

```go
package main

import (
    "context"
    "log"

    "github.com/GetStream/getstream-go/v3"
)

func main() {
    // Initialize the client
    client, err := getstream.NewClient("<your_api_key>", "<your_api_secret>")
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    feedsClient := client.Feeds()

    // Create a feed (or get its data if exists)
    feed := feedsClient.Feed("user", "john")
    feedResponse, err := feed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{})
    if err != nil {
        log.Fatal(err)
    }

    // Add activity
    activity, err := feedsClient.AddActivity(ctx, &getstream.AddActivityRequest{
        Text: getstream.PtrTo("Hello, Stream Feeds!"),
        Type: getstream.PtrTo("post"),
        Fids: []string{"user:john"},
    })
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("Activity created: %+v", activity.Data)
}
```

</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="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({
  comment_id: "comment_123",
  type: "love",
});
```

</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="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>

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

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

### Real-time Updates with State Layer

<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="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>

---

This page was last updated at 2025-08-15T14:13:57.110Z.

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