Activity Feeds v3 is in beta — try it out!

Follows

Follow & Unfollow

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.

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

Trying to follow a feed that is already followed will result in an error. Similarly, trying to unfollow a feed that is not followed, will result in an error.

When unfollowing a feed, all previous activities of that feed are removed from the timeline.

Querying Follows

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)

Follows Queryable Built-In Fields

nametypedescriptionsupported operationsexample
source_feedstring or list of stringsThe feed ID that is following$in, $eq{ source_feed: { $eq: 'messaging:general' } }
target_feedstring or list of stringsThe feed ID being followed$in, $eq{ target_feed: { $in: [ 'sports:news', 'tech:updates' ] } }
statusstring or list of stringsThe follow status$in, $eq{ status: { $in: [ 'accepted', 'pending', 'rejected' ] } }
created_atstring, must be formatted as an RFC3339 timestampThe 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.

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

Push Preferences on Follow

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 feed
  • none (default) - Don’t receive push notifications for activities from the followed feed

Note: The push_preference parameter controls future notifications from the followed feed, while skip_push controls whether the follow action itself triggers a notification.

Examples: Push Preferences vs Skip Push

Understanding the difference between push_preference and skip_push:

// 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 });
© Getstream.io, Inc. All Rights Reserved.