// Follow a user
let timeline = client.feed(group: "timeline", id: "john")
_ = try await timeline.follow(FeedId(group: "user", id: "tom"))
// Follow a stock
_ = try await timeline.follow(FeedId(group: "stock", id: "apple"))
// Follow with more fields
_ = try await timeline.follow(
FeedId(group: "stock", id: "apple"),
custom: ["reason": "investment"]
)Follow and Unfollow
Follow
The source feed should have a group that has "following" activity selector enabled, for example the built-in timeline group. The target feed should have a group that has "current" activity selector enabled, for example the built-in user group.
// Follow a user
val timeline = client.feed(group = "timeline", id = "john")
timeline.follow(FeedId(group = "user", id = "tom"))
// Follow a stock
timeline.follow(FeedId(group = "stock", id = "apple"))
// Follow with more fields
timeline.follow(
targetFid = FeedId(group = "stock", id = "apple"),
custom = mapOf("reason" to "investment")
)const timeline = client.feed("timeline", "john");
await timeline.getOrCreate();
// Follow a user
await timeline.follow("user:tom");
// Follow a stock
await timeline.follow("stock:apple");
// Follow with more fields
await timeline.follow("stock:apple", {
push_preference: "all",
custom: {
reason: "investment",
},
});
// Follow without Feed instance
await client.follow({
source: "timeline:alice",
target: "user:tom",
});const timeline = client.feed("timeline", "john");
await timeline.getOrCreate();
// Follow a user
await timeline.follow("user:tom");
// Follow a stock
await timeline.follow("stock:apple");
// Follow with more fields
await timeline.follow("stock:apple", {
push_preference: "all",
custom: {
reason: "investment",
},
});
// Follow without Feed instance
await client.follow({
source: "timeline:alice",
target: "user:tom",
});const timeline = client.feed("timeline", "john");
await timeline.getOrCreate();
// Follow a user
await timeline.follow("user:tom");
// Follow a stock
await timeline.follow("stock:apple");
// Follow with more fields
await timeline.follow("stock:apple", {
push_preference: "all",
custom: {
reason: "investment",
},
});
// Follow without Feed instance
await client.follow({
source: "timeline:alice",
target: "user:tom",
});// Follow a user
final timeline = client.feed(group: 'timeline', id: 'john');
await timeline.follow(targetFid: const FeedId(group: 'user', id: 'tom'));
// Follow a stock
await timeline.follow(targetFid: const FeedId(group: 'stock', id: 'apple'));
// Follow with more fields
await timeline.follow(
targetFid: const FeedId(group: 'stock', id: 'apple'),
custom: {'reason': 'investment'},
);const timeline = client.feeds.feed("timeline", "john");
await timeline.getOrCreate({
user_id: "john",
});
// Follow a user
await client.feeds.follow({
source: timeline.feed,
target: "user:tom",
});
// Follow a stock
await client.feeds.follow({
source: timeline.feed,
target: "stock:apple",
});
// Follow with more fields
await client.feeds.follow({
source: timeline.feed,
target: "stock:apple",
push_preference: "all",
custom: {
reason: "investment",
},
});// Create timeline feed
timeline := client.Feeds().Feed("timeline", "john")
_, err = timeline.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error getting/creating timeline feed:", err)
}
log.Println("Timeline feed created/retrieved successfully")
// Follow a user
_, err = client.Feeds().Follow(context.Background(), &getstream.FollowRequest{
Source: "timeline:john",
Target: "user:tom",
})
if err != nil {
log.Fatal("Error following user:", err)
}
log.Println("Successfully followed user:tom")
// Follow a stock
_, err = client.Feeds().Follow(context.Background(), &getstream.FollowRequest{
Source: "timeline:john",
Target: "stock:apple",
})
if err != nil {
log.Fatal("Error following stock:", err)
}
log.Println("Successfully followed stock:apple")
// Follow with more fields
_, err = client.Feeds().Follow(context.Background(), &getstream.FollowRequest{
Source: "timeline:john",
Target: "stock:apple",
PushPreference: getstream.PtrTo("all"),
Custom: map[string]any{
"reason": "investment",
},
})
if err != nil {
log.Fatal("Error following stock with custom fields:", err)
}
log.Println("Successfully followed stock:apple with custom fields")// Follow a user
FollowRequest followRequest =
FollowRequest.builder()
.source(USER_FEED_TYPE + testUserId)
.target(USER_FEED_TYPE + testUserId2)
.build();
SingleFollowResponse response = feeds.follow(followRequest).execute().getData();// Follow a user
$timeline = $feedsClient->feed('timeline', 'john');
$timeline->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john')
);
$response = $feedsClient->follow(
new GeneratedModels\FollowRequest(
source: 'timeline:john',
target: 'user:tom'
)
);
// Follow a stock
$response = $feedsClient->follow(
new GeneratedModels\FollowRequest(
source: 'timeline:john',
target: 'stock:apple'
)
);
// Follow with more fields
$response = $feedsClient->follow(
new GeneratedModels\FollowRequest(
source: 'timeline:john',
target: 'stock:apple',
pushPreference: 'all',
custom: (object)['reason' => 'investment']
)
);// Follow a user
var response = await _feedsV3Client.FollowAsync(
new FollowRequest
{
Source = $"user:{_testFeedId}",
Target = $"user:{_testFeedId2}"
}
);# Follow a user
response = self.client.feeds.follow(
source=f"{self.USER_FEED_TYPE}:{self.test_user_id}",
target=f"{self.USER_FEED_TYPE}:{self.test_user_id_2}",
)# Follow a user
follow_request = {
source: 'user:user123',
target: 'user:user456'
}
client.feeds.follow(follow_request)Trying to follow a feed that is already followed will result in an error. You can also use the getOrCreateFollows endpoint that provides an idempotent batch follow mechanism.
You do not need to call getOrCreate on the source or target feed before following. If either feed does not exist yet, the feed is created automatically when you call follow. This applies to both the single follow and batch follow endpoints.
Unfollow
When unfollowing a feed, all previous activities of that feed are removed from the timeline.
Trying to unfollow a feed that is not followed, will result in an error. You can also use the getOrCreateUnfollows endpoint that provides an idempotent batch unfollow mechanism.
let timeline = client.feed(group: "timeline", id: "john")
try await timeline.unfollow(FeedId(group: "user", id: "tom"))val timeline = client.feed(group = "timeline", id = "john")
timeline.unfollow(FeedId(group = "user", id = "tom"))const timeline = client.feed("timeline", "john");
await timeline.unfollow("user:tom");
// Unfollow without Feed instance
await client.unfollow({
source: "timeline:alice",
target: "user:tom",
});const timeline = client.feed("timeline", "john");
await timeline.unfollow("user:tom");
// Unfollow without Feed instance
await client.unfollow({
source: "timeline:alice",
target: "user:tom",
});const timeline = client.feed("timeline", "john");
await timeline.unfollow("user:tom");
// Unfollow without Feed instance
await client.unfollow({
source: "timeline:alice",
target: "user:tom",
});final timeline = client.feed(group: 'timeline', id: 'john');
await timeline.unfollow(targetFid: const FeedId(group: 'user', id: 'tom'));await client.feeds.unfollow({
source: timeline.feed,
target: "user:tom",
});_, err = client.Feeds().Unfollow(context.Background(), "timeline:john", "user:tom")UnfollowRequest unfollowRequest = UnfollowRequest.builder().build();
UnfollowResponse unfollowResponse =
feeds
.unfollow(USER_FEED_TYPE + testUserId, USER_FEED_TYPE + testUserId2, unfollowRequest)
.execute()
.getData();$response = $feedsClient->unfollow('timeline:john', 'user:tom');var unfollowResponse = await _feedsV3Client.UnfollowAsync(
$"user:{_testFeedId}",
$"user:{_testFeedId3}",
new { user_id = _testUserId }
);unfollow_response = self.client.feeds.unfollow(
f"{self.USER_FEED_TYPE}:{self.test_user_id}",
f"{self.USER_FEED_TYPE}:{self.test_user_id_2}",
)unfollow_response = client.feeds.unfollow(
'user:user123',
'user:user456'
)Querying Follows
// Do I follow a list of feeds
// My feed is timeline:john
let followQuery = FollowsQuery(
filter: .and([
.equal(.sourceFeed, "timeline:john"),
.in(.targetFeed, ["user:sara", "user:adam"])
])
)
let followList = client.followList(for: followQuery)
let page1 = try await followList.get()
let page2 = try await followList.queryMoreFollows()
let page1And2 = followList.state.follows
// Paginating through followers for a feed
// My feed is timeline:john
let followerQuery = FollowsQuery(
filter: .equal(.targetFeed, "timeline:john")
)
let followerList = client.followList(for: followerQuery)
let followerPage1 = try await followerList.get()// Do I follow a list of feeds
// My feed is timeline:john
val followQuery = FollowsQuery(
filter = Filters.and(
FollowsFilterField.sourceFeed.equal("timeline:john"),
FollowsFilterField.targetFeed.`in`("user:sara", "user:adam")
)
)
val followList = client.followList(query = followQuery)
val page1: Result<List<FollowData>> = followList.get()
val page2: Result<List<FollowData>> = followList.queryMoreFollows()
val page1And2 = followList.state.follows
// Paginating through followers for a feed
// My feed is timeline:john
val followerQuery = FollowsQuery(
filter = FollowsFilterField.targetFeed.equal("timeline:john")
)
val followerList = client.followList(query = followerQuery)
val followerPage1: Result<List<FollowData>> = followerList.get()const myTimeline = client.feed("timeline", "john");
await myTimeline.getOrCreate();
// Do I follow a list of feeds
const response = await client.queryFollows({
filter: {
source_feed: myTimeline.feed,
target_feed: { $in: ["user:sara", "user:adam"] },
},
});
console.log(response.follows);
const userFeed = client.feed("user", "john");
await userFeed.getOrCreate();
// Paginating through followers for a feed - won't store followers in state
const firstPage = await userFeed.queryFollowers({
limit: 20,
});
// Next page - won't store followers in state
const secondPage = await userFeed.queryFollowers({
limit: 20,
next: firstPage.next,
});
// or load when reading feed - will store followers in state
await feed.getOrCreate({
followers_pagination: {
limit: 10,
},
});
// and then load next pages (or first if followers are not yet loaded) - will store followers in state
await feed.loadNextPageFollowers({ limit: 10 });
console.log(feed.state.getLatestValue().followers);
// Filter by source - feeds that I follow - won't store followings in state
await myTimeline.queryFollowing({ limit: 10 });
// or load when reading feed - will store followings in state
await feed.getOrCreate({
following_pagination: {
limit: 10,
},
});
// and then load next pages (or first if followings are not yet loaded) - will store followings in state
await feed.loadNextPageFollowing({ limit: 10 });
console.log(feed.state.getLatestValue().following);const myTimeline = client.feed("timeline", "john");
await myTimeline.getOrCreate();
// Do I follow a list of feeds
const response = await client.queryFollows({
filter: {
source_feed: myTimeline.feed,
target_feed: { $in: ["user:sara", "user:adam"] },
},
});
console.log(response.follows);
const userFeed = client.feed("user", "john");
await userFeed.getOrCreate();
// Paginating through followers for a feed - won't store followers in state
const firstPage = await userFeed.queryFollowers({
limit: 20,
});
// Next page - won't store followers in state
const secondPage = await userFeed.queryFollowers({
limit: 20,
next: firstPage.next,
});
// or load when reading feed - will store followers in state
await feed.getOrCreate({
followers_pagination: {
limit: 10,
},
});
const {
followers,
follower_count,
followers_pagination,
is_loading_next_page,
has_next_page,
loadNextPage,
} = useFollowers(feed);
// and then load next pages (or first if followers are not yet loaded) - will store followers in state
await loadNextPage({ limit: 10 });
// Filter by source - feeds that I follow - won't store followings in state
await myTimeline.queryFollowing({ limit: 10 });
// or load when reading feed - will store followings in state
await feed.getOrCreate({
following_pagination: {
limit: 10,
},
});
const {
following,
following_count,
following_pagination,
is_loading_next_page,
has_next_page,
loadNextPage,
} = useFollowing(feed);
// and then load next pages (or first if followings are not yet loaded) - will store followings in state
await loadNextPage({ limit: 10 });const myTimeline = client.feed("timeline", "john");
await myTimeline.getOrCreate();
// Do I follow a list of feeds
const response = await client.queryFollows({
filter: {
source_feed: myTimeline.feed,
target_feed: { $in: ["user:sara", "user:adam"] },
},
});
console.log(response.follows);
const userFeed = client.feed("user", "john");
await userFeed.getOrCreate();
// Paginating through followers for a feed - won't store followers in state
const firstPage = await userFeed.queryFollowers({
limit: 20,
});
// Next page - won't store followers in state
const secondPage = await userFeed.queryFollowers({
limit: 20,
next: firstPage.next,
});
// or load when reading feed - will store followers in state
await feed.getOrCreate({
followers_pagination: {
limit: 10,
},
});
const {
followers,
follower_count,
followers_pagination,
is_loading_next_page,
has_next_page,
loadNextPage,
} = useFollowers(feed);
// and then load next pages (or first if followers are not yet loaded) - will store followers in state
await loadNextPage({ limit: 10 });
// Filter by source - feeds that I follow - won't store followings in state
await myTimeline.queryFollowing({ limit: 10 });
// or load when reading feed - will store followings in state
await feed.getOrCreate({
following_pagination: {
limit: 10,
},
});
const {
following,
following_count,
following_pagination,
is_loading_next_page,
has_next_page,
loadNextPage,
} = useFollowing(feed);
// and then load next pages (or first if followings are not yet loaded) - will store followings in state
await loadNextPage({ limit: 10 });// Do I follow a list of feeds
// My feed is timeline:john
const followQuery = FollowsQuery(
filter: Filter.and([
Filter.equal(FollowsFilterField.sourceFeed, 'timeline:john'),
Filter.in_(FollowsFilterField.targetFeed, ['user:sara', 'user:adam']),
]),
);
final followList = client.followList(followQuery);
final page1 = await followList.get();
final page2 = await followList.queryMoreFollows();
final page1And2 = followList.state.follows;
// Paginating through followers for a feed
// My feed is timeline:john
const followerQuery = FollowsQuery(
filter: Filter.equal(FollowsFilterField.targetFeed, 'timeline:john'),
);
final followerList = client.followList(followerQuery);
final followerPage1 = await followerList.get();const myTimeline = client.feeds.feed("timeline", "john");
await myTimeline.getOrCreate({
user_id: "john",
});
// Do I follow a list of feeds
const response = await client.feeds.queryFollows({
filter: {
source_feed: myTimeline.feed,
target_feed: { $in: ["user:sara", "user:adam"] },
},
});
console.log(response.follows);
const userFeed = client.feeds.feed("user", "john");
await userFeed.getOrCreate({
user_id: "john",
});
// Paginating through followers for a feed
const firstPage = await client.feeds.queryFollows({
filter: { target_feed: userFeed.feed },
limit: 20,
});
// Next page
const secondPage = await client.feeds.queryFollows({
filter: { target_feed: userFeed.feed },
limit: 20,
next: firstPage.next,
});
// Filter by source - feeds that I follow
await client.feeds.queryFollows({
filter: { source_feed: myTimeline.feed },
limit: 20,
});ctx := context.Background()
// Create timeline feed
myTimeline := client.Feeds().Feed("timeline", "john")
_, err = myTimeline.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error creating timeline feed:", err)
}
// Query follows to check if we follow a list of feeds
response, err := client.Feeds().QueryFollows(ctx, &getstream.QueryFollowsRequest{
Filter: map[string]any{
"source_feed": "timeline:john",
"target_feed": map[string]any{
"$in": []string{"user:sara", "user:adam"},
},
},
})
if err != nil {
log.Fatal("Error querying follows:", err)
}
log.Printf("Follows: %+v", response.Data.Follows)
// Create user feed
userFeed := client.Feeds().Feed("user", "john")
_, err = userFeed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error creating user feed:", err)
}
// Paginating through followers for a feed - first page
firstPage, err := client.Feeds().QueryFollows(ctx, &getstream.QueryFollowsRequest{
Filter: map[string]any{
"target_feed": "user:john",
},
Limit: getstream.PtrTo(20),
})
if err != nil {
log.Fatal("Error querying first page of follows:", err)
}
// Next page
secondPage, err := client.Feeds().QueryFollows(ctx, &getstream.QueryFollowsRequest{
Filter: map[string]any{
"target_feed": "user:john",
},
Limit: getstream.PtrTo(20),
Next: firstPage.Data.Next,
})
if err != nil {
log.Fatal("Error querying second page of follows:", err)
}
log.Printf("First page follows: %+v", firstPage.Data.Follows)
log.Printf("Second page follows: %+v", secondPage.Data.Follows)
// Filter by source - feeds that I follow
sourceFollows, err := client.Feeds().QueryFollows(ctx, &getstream.QueryFollowsRequest{
Filter: map[string]any{
"source_feed": "timeline:john",
},
Limit: getstream.PtrTo(20),
})
if err != nil {
log.Fatal("Error querying source follows:", err)
}
log.Printf("Source follows: %+v", sourceFollows.Data.Follows)// Query follows
QueryFollowsRequest request = QueryFollowsRequest.builder().limit(10).build();
QueryFollowsResponse response = feeds.queryFollows(request).execute().getData();$myTimeline = $feedsClient->feed('timeline', 'john');
$myTimeline->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john')
);
// Do I follow a list of feeds
$response = $feedsClient->queryFollows(
new GeneratedModels\QueryFollowsRequest(
filter: (object)[
'source_feed' => 'timeline:john',
'target_feed' => (object)['$in' => ['user:sara', 'user:adam']]
]
)
);
echo json_encode($response->getData()->follows);
$userFeed = $feedsClient->feed('user', 'john');
$userFeed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john')
);
// Paginating through followers for a feed
$firstPage = $feedsClient->queryFollows(
new GeneratedModels\QueryFollowsRequest(
filter: (object)['target_feed' => 'user:john'],
limit: 20
)
);
// Next page
$secondPage = $feedsClient->queryFollows(
new GeneratedModels\QueryFollowsRequest(
filter: (object)['target_feed' => 'user:john'],
limit: 20,
next: $firstPage->getData()->next
)
);
// Filter by source - feeds that I follow
$sourceFollows = $feedsClient->queryFollows(
new GeneratedModels\QueryFollowsRequest(
filter: (object)['source_feed' => 'timeline:john'],
limit: 20
)
);// Query follows
var response = await _feedsV3Client.QueryFollowsAsync(
new QueryFollowsRequest
{
Limit = 10
}
);# Query follows
response = self.client.feeds.query_follows(
limit=10,
filter={
"source_feed": f"{self.USER_FEED_TYPE}:{self.test_user_id}"
}
)# Query follows
# First page - paginating through followers for a feed
first_page = client.feeds.query_follows(
GetStream::Generated::Models::QueryFollowsRequest.new(
filter: { target_feed: 'user:john' },
limit: 20
)
)
# Second page using next cursor from first page
if first_page.next
second_page = client.feeds.query_follows(
GetStream::Generated::Models::QueryFollowsRequest.new(
filter: { target_feed: 'user:john' },
limit: 20,
next: first_page.next
)
)
end
# Filter by source - feeds that I follow
source_follows = client.feeds.query_follows(
GetStream::Generated::Models::QueryFollowsRequest.new(
filter: { source_feed: 'timeline:john' },
limit: 20
)
)Follows Queryable Built-In Fields
| name | type | description | supported operations | example |
|---|---|---|---|---|
source_feed | string or list of strings | The feed ID that is following | $in, $eq | { source_feed: { $eq: 'messaging:general' } } |
target_feed | string or list of strings | The feed ID being followed | $in, $eq | { target_feed: { $in: [ 'sports:news', 'tech:updates' ] } } |
status | string or list of strings | The follow status | $in, $eq | { status: { $in: [ 'accepted', 'pending', 'rejected' ] } } |
created_at | string, must be formatted as an RFC3339 timestamp | The time the follow relationship was created | $eq, $gt, $gte, $lt, $lte | { created_at: { $gte: '2023-12-04T09:30:20.45Z' } } |
Follow Requests
Some apps require the user's approval for following them.
// Sara needs to configure the feed with visibility = followers for enabling follow requests
let saraFeed = saraClient.feed(
for: .init(
group: "user",
id: "sara",
data: .init(visibility: .followers)
)
)
try await saraFeed.getOrCreate()
// Adam requesting to follow the feed
let adamTimeline = adamClient.feed(group: "timeline", id: "adam")
try await adamTimeline.getOrCreate()
let followRequest = try await adamTimeline.follow(saraFeed.feed) // user:sara
print(followRequest.status) // .pending
// Sara accepting
try await saraFeed.acceptFollow(
adamTimeline.feed, // timeline:adam
role: "feed_member" // optional
)
// or rejecting the request
try await saraFeed.rejectFollow(adamTimeline.feed) // timeline:adam// Sara needs to configure the feed with visibility = followers for enabling follow requests
val saraFeed = saraClient.feed(
query = FeedQuery(
group = "user",
id = "sara",
data = FeedInputData(visibility = FeedVisibility.Followers)
)
)
saraFeed.getOrCreate()
// Adam requesting to follow the feed
val adamTimeline = adamClient.feed(group = "timeline", id = "adam")
adamTimeline.getOrCreate()
val followRequest = adamTimeline.follow(saraFeed.fid) // user:sara
println(followRequest.getOrNull()?.status) // FollowStatus.PENDING
// Sara accepting
saraFeed.acceptFollow(
sourceFid = adamTimeline.fid, // timeline:adam
role = "feed_member" // optional
)
// or rejecting the request
saraFeed.rejectFollow(adamTimeline.fid) // timeline:adamconst saraFeed = saraClient.feed("user", uuidv4());
await saraFeed.getOrCreate({
// You need to set followers visibility to have follow requests
data: { visibility: "followers" },
});
const adamTimeline = adamClient.feed("timeline", uuidv4());
await adamTimeline.getOrCreate();
const followRequest = await adamTimeline.follow(saraFeed.feed);
console.log(followRequest.follow.status); // pending
await saraClient.acceptFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
// Optionally provide role
follower_role: "feed_member",
});
await saraClient.rejectFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
});const saraFeed = saraClient.feed("user", uuidv4());
await saraFeed.getOrCreate({
// You need to set followers visibility to have follow requests
data: { visibility: "followers" },
});
const adamTimeline = adamClient.feed("timeline", uuidv4());
await adamTimeline.getOrCreate();
const followRequest = await adamTimeline.follow(saraFeed.feed);
console.log(followRequest.follow.status); // pending
await saraClient.acceptFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
// Optionally provide role
follower_role: "feed_member",
});
await saraClient.rejectFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
});const saraFeed = saraClient.feed("user", uuidv4());
await saraFeed.getOrCreate({
// You need to set followers visibility to have follow requests
data: { visibility: "followers" },
});
const adamTimeline = adamClient.feed("timeline", uuidv4());
await adamTimeline.getOrCreate();
const followRequest = await adamTimeline.follow(saraFeed.feed);
console.log(followRequest.follow.status); // pending
await saraClient.acceptFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
// Optionally provide role
follower_role: "feed_member",
});
await saraClient.rejectFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
});// Sara needs to configure the feed with visibility = followers for enabling follow requests
const saraFeedQuery = FeedQuery(
fid: FeedId(group: 'user', id: 'sara'),
data: FeedInputData(visibility: FeedVisibility.followers),
);
final saraFeed = saraClient.feedFromQuery(saraFeedQuery);
await saraFeed.getOrCreate();
// Adam requesting to follow the feed
final adamTimeline = adamClient.feed(group: 'timeline', id: 'adam');
await adamTimeline.getOrCreate();
final followRequest =
await adamTimeline.follow(targetFid: saraFeed.fid); // user:sara
print(followRequest.getOrNull()?.status); // .pending
// Sara accepting
await saraFeed.acceptFollow(
sourceFid: adamTimeline.fid, // timeline:adam
role: 'feed_member', // optional
);
// or rejecting the request
await saraFeed.rejectFollow(sourceFid: adamTimeline.fid); // timeline:adamconst saraFeed = client.feeds.feed("user", uuidv4());
await saraFeed.getOrCreate({
// You need to set followers visibility to have follow requests
data: { visibility: "followers" },
user_id: "sara",
});
const adamTimeline = client.feeds.feed("timeline", uuidv4());
await adamTimeline.getOrCreate({
user_id: "adam",
});
const followRequest = await client.feeds.follow({
source: adamTimeline.feed,
target: saraFeed.feed,
});
console.log(followRequest.follow.status); // pending
await client.feeds.acceptFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
// Optionally provide role
follower_role: "feed_member",
});
await client.feeds.rejectFollow({
source: adamTimeline.feed,
target: saraFeed.feed,
});ctx := context.Background()
saraFeed := client.Feeds().Feed("user", "sara")
_, err = saraFeed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
Data: &getstream.FeedInput{
Visibility: getstream.PtrTo("followers"),
},
UserID: getstream.PtrTo("sara"),
})
if err != nil {
log.Fatal("Error creating sara feed:", err)
}
adamTimeline := client.Feeds().Feed("timeline", "adam")
_, err = adamTimeline.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("adam"),
})
if err != nil {
log.Fatal("Error creating adam timeline feed:", err)
}
// Create follow request from adamTimeline to saraFeed
followRequest, err := client.Feeds().Follow(ctx, &getstream.FollowRequest{
Source: "timeline:adam",
Target: "user:sara",
})
if err != nil {
log.Fatal("Error creating follow request:", err)
}
fmt.Printf("Follow request status: %s\n", followRequest.Data.Follow.Status)
// Accept follow request and set follower's role
_, err = client.Feeds().AcceptFollow(ctx, &getstream.AcceptFollowRequest{
Source: "timeline:adam",
Target: "user:sara",
FollowerRole: getstream.PtrTo("feed_member"),
})
if err != nil {
log.Fatal("Error accepting follow request:", err)
}
// Reject follow request
_, err = client.Feeds().RejectFollow(ctx, &getstream.RejectFollowRequest{
Source: "timeline:adam",
Target: "user:sara",
})
if err != nil {
log.Fatal("Error rejecting follow request:", err)
}// Sara needs to configure the feed with visibility = followers for enabling follow requests
GetOrCreateFeedRequest saraFeedRequest = GetOrCreateFeedRequest.builder()
.userID("sara")
.data(FeedInput.builder()
.visibility("followers")
.build())
.build();
feeds.getOrCreateFeed("user", "sara", saraFeedRequest).execute();
// Adam requesting to follow the feed
GetOrCreateFeedRequest adamFeedRequest = GetOrCreateFeedRequest.builder()
.userID("adam")
.build();
feeds.getOrCreateFeed("timeline", "adam", adamFeedRequest).execute();
// Create follow request from adamTimeline to saraFeed
FollowRequest followRequest = FollowRequest.builder()
.source("timeline:adam")
.target("user:sara")
.build();
SingleFollowResponse followResponse = feeds.follow(followRequest).execute().getData();
System.out.println(followResponse.getFollow().getStatus()); // pending
// Sara accepting
AcceptFollowRequest acceptRequest = AcceptFollowRequest.builder()
.source("timeline:adam")
.target("user:sara")
.followerRole("feed_member") // optional
.build();
feeds.acceptFollow(acceptRequest).execute();
// or rejecting the request
RejectFollowRequest rejectRequest = RejectFollowRequest.builder()
.source("timeline:adam")
.target("user:sara")
.build();
feeds.rejectFollow(rejectRequest).execute();// Sara needs to configure the feed with visibility = followers for enabling follow requests
$saraFeed = $feedsClient->feed('user', 'sara');
$saraFeed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(
userID: 'sara',
data: new GeneratedModels\FeedInput(visibility: 'followers')
)
);
// Adam requesting to follow the feed
$adamTimeline = $feedsClient->feed('timeline', 'adam');
$adamTimeline->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'adam')
);
$followRequest = $feedsClient->follow(
new GeneratedModels\FollowRequest(
source: 'timeline:adam',
target: 'user:sara'
)
);
echo $followRequest->getData()->follow->status; // pending
// Sara accepting
$acceptResponse = $feedsClient->acceptFollow(
new GeneratedModels\AcceptFollowRequest(
source: 'timeline:adam',
target: 'user:sara',
followerRole: 'feed_member' // optional
)
);
// or rejecting the request
$rejectResponse = $feedsClient->rejectFollow(
new GeneratedModels\RejectFollowRequest(
source: 'timeline:adam',
target: 'user:sara'
)
);// Sara needs to configure the feed with visibility = followers for enabling follow requests
await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: "sara",
request: new GetOrCreateFeedRequest
{
UserID = "sara",
Data = new FeedInput { Visibility = "followers" }
}
);
// Adam requesting to follow the feed
await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "timeline",
FeedID: "adam",
request: new GetOrCreateFeedRequest { UserID = "adam" }
);
// Create follow request from adamTimeline to saraFeed
var followResponse = await _feedsV3Client.FollowAsync(
new FollowRequest
{
Source = "timeline:adam",
Target = "user:sara"
}
);
Console.WriteLine(followResponse.Follow.Status); // pending
// Sara accepting
await _feedsV3Client.AcceptFollowAsync(
new AcceptFollowRequest
{
Source = "timeline:adam",
Target = "user:sara",
FollowerRole = "feed_member" // optional
}
);
// or rejecting the request
await _feedsV3Client.RejectFollowAsync(
new RejectFollowRequest
{
Source = "timeline:adam",
Target = "user:sara"
}
);# Sara needs to configure the feed with visibility = followers for enabling follow requests
feeds.get_or_create_feed(
feed_group="user",
feed_id="sara",
user_id="sara",
data={"visibility": "followers"}
)
# Adam requesting to follow the feed
feeds.get_or_create_feed(
feed_group="timeline",
feed_id="adam",
user_id="adam"
)
# Create follow request from adamTimeline to saraFeed
follow_response = feeds.follow(
source="timeline:adam",
target="user:sara"
)
print(follow_response["follow"]["status"]) # pending
# Sara accepting
feeds.accept_follow(
source="timeline:adam",
target="user:sara",
follower_role="feed_member" # optional
)
# or rejecting the request
feeds.reject_follow(
source="timeline:adam",
target="user:sara"
)# Sara needs to configure the feed with visibility = followers for enabling follow requests
client.feeds.get_or_create_feed(
"user",
"sara",
GetStream::Generated::Models::GetOrCreateFeedRequest.new(
user_id: "sara",
data: { "visibility" => "followers" }
)
)
# Adam requesting to follow the feed
client.feeds.get_or_create_feed(
"timeline",
"adam",
GetStream::Generated::Models::GetOrCreateFeedRequest.new(
user_id: "adam"
)
)
# Create follow request from adamTimeline to saraFeed
follow_response = client.feeds.follow(
GetStream::Generated::Models::FollowRequest.new(
source: "timeline:adam",
target: "user:sara"
)
)
puts follow_response.data.follow.status # pending
# Sara accepting
client.feeds.accept_follow(
GetStream::Generated::Models::AcceptFollowRequest.new(
source: "timeline:adam",
target: "user:sara",
follower_role: "feed_member" # optional
)
)
# or rejecting the request
client.feeds.reject_follow(
GetStream::Generated::Models::RejectFollowRequest.new(
source: "timeline:adam",
target: "user:sara"
)
)Push Preferences on Follow
Understanding the difference between push_preference, skip_push and create_notification_activity:
When following a feed, you can set push_preference to control push notifications for future activities from that feed:
all- Receive push notifications for all activities from the followed feednone(default) - Don't receive push notifications for activities from the followed feed
The skip_push controls whether the follow action itself triggers a notification.
The create_notification_activity controls whether the follow action creates an activity on the source feed author's notification feed.
Note: You usually don't want to set skip_push and create_notification_activity true at the same time, for more information see the Push Overview page
// Scenario 1: Follow a user and receive notifications for their future activities
await timeline.follow("user:alice", {
push_preference: "all", // You'll get push notifications for Alice's future posts
});
// Scenario 2: Follow a user but don't get notifications for their activities
await timeline.follow("user:bob", {
push_preference: "none", // You won't get push notifications for Bob's future posts
});
// Scenario 3: Follow a user silently
await timeline.follow("user:charlie", {
skip_push: true, // Charlie won't get a "you have a new follower" notification
push_preference: "all", // But you'll still get notifications for Charlie's future posts
});
// Scenario 4: Silent follow with no future notifications
await timeline.follow("user:diana", {
skip_push: true, // Diana won't know you followed her
push_preference: "none", // And you won't get notifications for her posts
});
// Scenario 5: Follow a user and create notification activity for Charile
await timeline.follow("user:charlie", {
skip_push: true, // Charlie won't get a "you have a new follower" notification
create_notification_activity: true, // Charlie's notification feed will have a new activity
push_preference: "all", // But you'll still get notifications for Charlie's future posts
});Built-in fields of follows
FollowResponse
| Name | Type | Description | Constraints |
|---|---|---|---|
created_at | number | When the follow relationship was created | Required |
custom | object | Custom data for the follow relationship | - |
follower_role | string | Role of the follower (source user) in the follow relationship | Required |
push_preference | string (all, none) | Push preference for notifications | Required |
request_accepted_at | number | When the follow request was accepted | - |
request_rejected_at | number | When the follow request was rejected | - |
source_feed | FeedResponse | Source feed object | Required |
status | string (accepted, pending, rejected) | Status of the follow relationship | Required |
target_feed | FeedResponse | Target feed object | Required |
updated_at | number | When the follow relationship was last updated | Required |
Follow Suggestions
Stream provides intelligent follow suggestions to help users discover feeds they might want to follow based on their activity and social graph.
Note: The maximum limit for follow suggestions is 50. If a higher limit is requested, it will be automatically capped at 50.
// Get follow suggestions for a user
let suggestions = try await client.getFollowSuggestions(
feedGroupId: "user",
limit: 10,
userId: "john"
)
for suggestion in suggestions.suggestions {
print("Suggested feed: \(suggestion.fid)")
print("Recommendation score: \(suggestion.recommendationScore)")
print("Reason: \(suggestion.reason)")
}// Get follow suggestions for a user
val suggestions = client.getFollowSuggestions(
feedGroupId = "user",
limit = 10,
userId = "john"
)
suggestions.suggestions.forEach { suggestion ->
println("Suggested feed: ${suggestion.fid}")
println("Recommendation score: ${suggestion.recommendationScore}")
println("Reason: ${suggestion.reason}")
}// Get follow suggestions for a user
const suggestions = await client.getFollowSuggestions({
feed_group_id: "user",
limit: 10,
});
console.log("Algorithm used:", suggestions.algorithm_used);
console.log("Duration:", suggestions.duration);
suggestions.suggestions.forEach((suggestion) => {
console.log("Suggested feed:", suggestion.feed);
console.log("Name:", suggestion.name);
console.log("Description:", suggestion.description);
console.log("Follower count:", suggestion.follower_count);
console.log("Recommendation score:", suggestion.recommendation_score);
console.log("Reason:", suggestion.reason);
console.log("Algorithm scores:", suggestion.algorithm_scores);
});// Get follow suggestions for a user
const suggestions = await client.getFollowSuggestions({
feed_group_id: "user",
limit: 10,
});
console.log("Algorithm used:", suggestions.algorithm_used);
console.log("Duration:", suggestions.duration);
suggestions.suggestions.forEach((suggestion) => {
console.log("Suggested feed:", suggestion.feed);
console.log("Name:", suggestion.name);
console.log("Description:", suggestion.description);
console.log("Follower count:", suggestion.follower_count);
console.log("Recommendation score:", suggestion.recommendation_score);
console.log("Reason:", suggestion.reason);
console.log("Algorithm scores:", suggestion.algorithm_scores);
});// Get follow suggestions for a user
const suggestions = await client.getFollowSuggestions({
feed_group_id: "user",
limit: 10,
});
console.log("Algorithm used:", suggestions.algorithm_used);
console.log("Duration:", suggestions.duration);
suggestions.suggestions.forEach((suggestion) => {
console.log("Suggested feed:", suggestion.feed);
console.log("Name:", suggestion.name);
console.log("Description:", suggestion.description);
console.log("Follower count:", suggestion.follower_count);
console.log("Recommendation score:", suggestion.recommendation_score);
console.log("Reason:", suggestion.reason);
console.log("Algorithm scores:", suggestion.algorithm_scores);
});// Get follow suggestions for a user
final suggestions = await client.getFollowSuggestions(
feedGroupId: 'user',
limit: 10,
userId: 'john',
);
print('Algorithm used: ${suggestions.algorithmUsed}');
print('Duration: ${suggestions.duration}');
for (final suggestion in suggestions.suggestions) {
print('Suggested feed: ${suggestion.fid}');
print('Name: ${suggestion.name}');
print('Description: ${suggestion.description}');
print('Follower count: ${suggestion.followerCount}');
print('Recommendation score: ${suggestion.recommendationScore}');
print('Reason: ${suggestion.reason}');
print('Algorithm scores: ${suggestion.algorithmScores}');
}// Get follow suggestions for a user
const suggestions = await client.feeds.getFollowSuggestions({
feed_group_id: "user",
limit: 10,
user_id: "john",
});
console.log("Algorithm used:", suggestions.algorithm_used);
console.log("Duration:", suggestions.duration);
suggestions.suggestions.forEach((suggestion) => {
console.log("Suggested feed:", suggestion.feed);
console.log("Name:", suggestion.name);
console.log("Description:", suggestion.description);
console.log("Follower count:", suggestion.follower_count);
console.log("Recommendation score:", suggestion.recommendation_score);
console.log("Reason:", suggestion.reason);
console.log("Algorithm scores:", suggestion.algorithm_scores);
});// Get follow suggestions for a user
suggestions, err := client.Feeds().GetFollowSuggestions(context.Background(), &getstream.GetFollowSuggestionsRequest{
FeedGroupId: "user",
Limit: getstream.PtrTo(10),
UserId: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error getting follow suggestions:", err)
}
fmt.Printf("Algorithm used: %s\n", suggestions.Data.AlgorithmUsed)
fmt.Printf("Duration: %s\n", suggestions.Data.Duration)
for _, suggestion := range suggestions.Data.Suggestions {
fmt.Printf("Suggested feed: %s\n", suggestion.Fid)
fmt.Printf("Name: %s\n", suggestion.Name)
fmt.Printf("Description: %s\n", suggestion.Description)
fmt.Printf("Follower count: %d\n", suggestion.FollowerCount)
fmt.Printf("Recommendation score: %.2f\n", suggestion.RecommendationScore)
fmt.Printf("Reason: %s\n", suggestion.Reason)
fmt.Printf("Algorithm scores: %+v\n", suggestion.AlgorithmScores)
}// Get follow suggestions for a user
GetFollowSuggestionsRequest request = GetFollowSuggestionsRequest.builder()
.feedGroupId("user")
.limit(10)
.userId("john")
.build();
GetFollowSuggestionsResponse response = feeds.getFollowSuggestions(request).execute().getData();
System.out.println("Algorithm used: " + response.getAlgorithmUsed());
System.out.println("Duration: " + response.getDuration());
for (FollowSuggestion suggestion : response.getSuggestions()) {
System.out.println("Suggested feed: " + suggestion.getFid());
System.out.println("Name: " + suggestion.getName());
System.out.println("Description: " + suggestion.getDescription());
System.out.println("Follower count: " + suggestion.getFollowerCount());
System.out.println("Recommendation score: " + suggestion.getRecommendationScore());
System.out.println("Reason: " + suggestion.getReason());
System.out.println("Algorithm scores: " + suggestion.getAlgorithmScores());
}// Get follow suggestions for a user
$suggestions = $feedsClient->getFollowSuggestions(
new GeneratedModels\GetFollowSuggestionsRequest(
feedGroupId: 'user',
limit: 10,
userId: 'john'
)
);
echo "Algorithm used: " . $suggestions->getData()->algorithmUsed . "\n";
echo "Duration: " . $suggestions->getData()->duration . "\n";
foreach ($suggestions->getData()->suggestions as $suggestion) {
echo "Suggested feed: " . $suggestion->fid . "\n";
echo "Name: " . $suggestion->name . "\n";
echo "Description: " . $suggestion->description . "\n";
echo "Follower count: " . $suggestion->followerCount . "\n";
echo "Recommendation score: " . $suggestion->recommendationScore . "\n";
echo "Reason: " . $suggestion->reason . "\n";
echo "Algorithm scores: " . json_encode($suggestion->algorithmScores) . "\n";
}// Get follow suggestions for a user
var response = await _feedsV3Client.GetFollowSuggestionsAsync(
new GetFollowSuggestionsRequest
{
FeedGroupId = "user",
Limit = 10,
UserId = "john"
}
);
Console.WriteLine($"Algorithm used: {response.AlgorithmUsed}");
Console.WriteLine($"Duration: {response.Duration}");
foreach (var suggestion in response.Suggestions)
{
Console.WriteLine($"Suggested feed: {suggestion.Fid}");
Console.WriteLine($"Name: {suggestion.Name}");
Console.WriteLine($"Description: {suggestion.Description}");
Console.WriteLine($"Follower count: {suggestion.FollowerCount}");
Console.WriteLine($"Recommendation score: {suggestion.RecommendationScore}");
Console.WriteLine($"Reason: {suggestion.Reason}");
Console.WriteLine($"Algorithm scores: {JsonSerializer.Serialize(suggestion.AlgorithmScores)}");
}# Get follow suggestions for a user
suggestions = client.feeds.get_follow_suggestions(
feed_group_id="user",
limit=10,
user_id="john"
)
print(f"Algorithm used: {suggestions.algorithm_used}")
print(f"Duration: {suggestions.duration}")
for suggestion in suggestions.suggestions:
print(f"Suggested feed: {suggestion.fid}")
print(f"Name: {suggestion.name}")
print(f"Description: {suggestion.description}")
print(f"Follower count: {suggestion.follower_count}")
print(f"Recommendation score: {suggestion.recommendation_score}")
print(f"Reason: {suggestion.reason}")
print(f"Algorithm scores: {suggestion.algorithm_scores}")# Get follow suggestions for a user
suggestions = client.feeds.get_follow_suggestions(
feed_group_id: 'user',
limit: 10,
user_id: 'john'
)
puts "Algorithm used: #{suggestions.algorithm_used}"
puts "Duration: #{suggestions.duration}"
suggestions.suggestions.each do |suggestion|
puts "Suggested feed: #{suggestion.fid}"
puts "Name: #{suggestion.name}"
puts "Description: #{suggestion.description}"
puts "Follower count: #{suggestion.follower_count}"
puts "Recommendation score: #{suggestion.recommendation_score}"
puts "Reason: #{suggestion.reason}"
puts "Algorithm scores: #{suggestion.algorithm_scores}"
endResponse Fields
The follow suggestions response includes:
suggestions: Array of suggested feeds to followfeed: Feed identifiername: Feed namedescription: Feed descriptionvisibility: Feed visibility settingmember_count: Number of membersfollower_count: Number of followersfollowing_count: Number of feeds this feed followscreated_at: When the feed was createdupdated_at: When the feed was last updatedrecommendation_score: Combined recommendation score (0-1)reason: Human-readable reason for the suggestionalgorithm_scores: Individual algorithm scores
algorithm_used: The algorithm used to generate suggestionsduration: Request processing time
Algorithm Types
Stream's follow suggestions use a sophisticated multi-algorithm approach with weighted scoring:
popularity(Weight: 0.3): Based on follower count and engagement- Calculates normalized follower count relative to the most popular feed in your app
- Score = min(follower_count / max_follower_count, 1.0)
- Helps surface trending and popular content
friend-of-friend(Weight: 0.7): Based on social connections and mutual follows- Analyzes how many of your followed feeds also follow the suggested feed
- Score = mutual_follows / your_total_follows
- Leverages social proof and network effects
combined: Uses multiple algorithms with weighted scoring- Final score = (popularity_score × 0.3 + friend_of_friend_score × 0.7) / total_weight
- Provides balanced recommendations combining popularity and social relevance
Note: Additional algorithms will be added in future releases to provide even more sophisticated recommendations.
Scoring System
The recommendation system uses a sophisticated scoring mechanism:
- Individual Algorithm Scores: Each algorithm calculates a score from 0.0 to 1.0
- Weighted Combination: Scores are combined using configurable weights
- Normalization: Final scores are normalized to ensure fair comparison
- Filtering: Only feeds with positive combined scores are included
- Ranking: Results are sorted by combined score in descending order
Features
- Excludes feeds already followed by the user
- Excludes user's own feeds
- Sophisticated algorithm to find feeds to follow
Batch follow & unfollow
getOrCreateFollows/getOrCreateUnfollows endpoints allow creating a maximum of 100 follow/unfollow at once.
These are idempotent endpoints (as opposed to follow and unfollow), trying to follow/unfollow a feed that's already/not yet followed won't cause errors.
// Batch follow
val requests = listOf(
FollowRequest(
source = timeline.fid.rawValue,
target = fid1.rawValue,
),
FollowRequest(
source = timeline.fid.rawValue,
target = fid2.rawValue,
),
)
client.getOrCreateFollows(FollowBatchRequest(requests))
.onSuccess { batchData ->
println("Created follows: ${batchData.created}")
println("Follows: ${batchData.follows}")
}
// Batch unfollow
val unfollowPairs = listOf(
FollowPair(
source = timeline.fid.rawValue,
target = fid1.rawValue,
),
FollowPair(
source = timeline.fid.rawValue,
target = fid2.rawValue,
),
)
client.getOrCreateUnfollows(UnfollowBatchRequest(unfollowPairs))
.onSuccess { follows ->
println("Follows that were removed: $follows")
}const response = await client.getOrCreateFollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
// Optional
push_preference: "all",
custom: {
reason: "investment",
},
},
{
source: timeline.feed,
target: feed2.feed,
},
],
});
console.log("Created follows:", response.created);
console.log("Follows:", response.follows);
await client.getOrCreateUnfollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
},
],
});
console.log("Follows that were removed:", response.follows);const response = await client.getOrCreateFollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
// Optional
push_preference: "all",
custom: {
reason: "investment",
},
},
{
source: timeline.feed,
target: feed2.feed,
},
],
});
console.log("Created follows:", response.created);
console.log("Follows:", response.follows);
await client.getOrCreateUnfollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
},
],
});
console.log("Follows that were removed:", response.follows);const response = await client.getOrCreateFollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
// Optional
push_preference: "all",
custom: {
reason: "investment",
},
},
{
source: timeline.feed,
target: feed2.feed,
},
],
});
console.log("Created follows:", response.created);
console.log("Follows:", response.follows);
await client.getOrCreateUnfollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
},
],
});
console.log("Follows that were removed:", response.follows);const response = await client.feeds.getOrCreateFollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
// Optional
push_preference: "all",
custom: {
reason: "investment",
},
},
{
source: timeline.feed,
target: feed2.feed,
},
],
});
console.log("Created follows:", response.created);
console.log("Follows:", response.follows);
await client.feeds.getOrCreateUnfollows({
follows: [
{
source: timeline.feed,
target: feed.feed,
},
],
});
console.log("Follows that were removed:", response.follows);ctx := context.Background()
// Batch create follows
response, err := client.Feeds().GetOrCreateFollows(ctx, &getstream.GetOrCreateFollowsRequest{
Follows: []getstream.FollowRequest{
{
Source: "timeline:john",
Target: "user:tom",
// Optional
PushPreference: getstream.PtrTo("all"),
Custom: map[string]any{
"reason": "investment",
},
},
{
Source: "timeline:john",
Target: "stock:apple",
},
},
})
if err != nil {
log.Fatal("Error creating follows:", err)
}
fmt.Printf("Created follows: %d\n", len(response.Data.Created))
fmt.Printf("Total follows: %d\n", len(response.Data.Follows))
// Batch remove follows
unfollowResponse, err := client.Feeds().GetOrCreateUnfollows(ctx, &getstream.GetOrCreateUnfollowsRequest{
Follows: []getstream.FollowPair{
{
Source: "timeline:john",
Target: "user:tom",
},
},
})
if err != nil {
log.Fatal("Error removing follows:", err)
}
fmt.Printf("Follows that were removed: %d\n", len(unfollowResponse.Data.Follows))# Batch create follows
response = client.feeds.get_or_create_follows(
follows=[
{
"source": "timeline:john",
"target": "user:tom",
# Optional
"push_preference": "all",
"custom": {
"reason": "investment"
}
},
{
"source": "timeline:john",
"target": "stock:apple"
}
]
)
print(f"Created follows: {len(response['created'])}")
print(f"Total follows: {len(response['follows'])}")
# Batch remove follows
unfollow_response = client.feeds.get_or_create_unfollows(
follows=[
{
"source": "timeline:john",
"target": "user:tom"
}
]
)
print(f"Follows that were removed: {len(unfollow_response['follows'])}")// Batch create follows
$response = $feedsClient->getOrCreateFollows(
new GeneratedModels\GetOrCreateFollowsRequest(
follows: [
new GeneratedModels\FollowInput(
source: 'timeline:john',
target: 'user:tom',
// Optional
pushPreference: 'all',
custom: (object)['reason' => 'investment']
),
new GeneratedModels\FollowInput(
source: 'timeline:john',
target: 'stock:apple'
)
]
)
);
echo "Created follows: " . count($response->getData()->created) . "\n";
echo "Total follows: " . count($response->getData()->follows) . "\n";
// Batch remove follows
$unfollowResponse = $feedsClient->getOrCreateUnfollows(
new GeneratedModels\GetOrCreateUnfollowsRequest(
follows: [
new GeneratedModels\FollowInput(
source: 'timeline:john',
target: 'user:tom'
)
]
)
);
echo "Follows that were removed: " . count($unfollowResponse->getData()->follows) . "\n";// Batch create follows
GetOrCreateFollowsRequest followsRequest = GetOrCreateFollowsRequest.builder()
.follows(Arrays.asList(
FollowInput.builder()
.source("timeline:john")
.target("user:tom")
// Optional
.pushPreference("all")
.custom(Map.of("reason", "investment"))
.build(),
FollowInput.builder()
.source("timeline:john")
.target("stock:apple")
.build()
))
.build();
GetOrCreateFollowsResponse response = feeds.getOrCreateFollows(followsRequest).execute().getData();
System.out.println("Created follows: " + response.getCreated().size());
System.out.println("Total follows: " + response.getFollows().size());
// Batch remove follows
GetOrCreateUnfollowsRequest unfollowsRequest = GetOrCreateUnfollowsRequest.builder()
.follows(Arrays.asList(
FollowInput.builder()
.source("timeline:john")
.target("user:tom")
.build()
))
.build();
GetOrCreateUnfollowsResponse unfollowResponse = feeds.getOrCreateUnfollows(unfollowsRequest).execute().getData();
System.out.println("Follows that were removed: " + unfollowResponse.getFollows().size());// Batch create follows
var response = await _feedsV3Client.GetOrCreateFollowsAsync(
new GetOrCreateFollowsRequest
{
Follows = new List<FollowInput>
{
new FollowInput
{
Source = "timeline:john",
Target = "user:tom",
// Optional
PushPreference = "all",
Custom = new Dictionary<string, object>
{
{ "reason", "investment" }
}
},
new FollowInput
{
Source = "timeline:john",
Target = "stock:apple"
}
}
}
);
Console.WriteLine($"Created follows: {response.Created.Count}");
Console.WriteLine($"Total follows: {response.Follows.Count}");
// Batch remove follows
var unfollowResponse = await _feedsV3Client.GetOrCreateUnfollowsAsync(
new GetOrCreateUnfollowsRequest
{
Follows = new List<FollowInput>
{
new FollowInput
{
Source = "timeline:john",
Target = "user:tom"
}
}
}
);
Console.WriteLine($"Follows that were removed: {unfollowResponse.Follows.Count}");# Batch create follows
response = client.feeds.get_or_create_follows(
GetStream::Generated::Models::GetOrCreateFollowsRequest.new(
follows: [
GetStream::Generated::Models::FollowInput.new(
source: 'timeline:john',
target: 'user:tom',
# Optional
push_preference: 'all',
custom: { 'reason' => 'investment' }
),
GetStream::Generated::Models::FollowInput.new(
source: 'timeline:john',
target: 'stock:apple'
)
]
)
)
puts "Created follows: #{response.data.created.length}"
puts "Total follows: #{response.data.follows.length}"
# Batch remove follows
unfollow_response = client.feeds.get_or_create_unfollows(
GetStream::Generated::Models::GetOrCreateUnfollowsRequest.new(
follows: [
GetStream::Generated::Models::FollowInput.new(
source: 'timeline:john',
target: 'user:tom'
)
]
)
)
puts "Follows that were removed: #{unfollow_response.data.follows.length}"