import io.getstream.services.FeedsImpl;
import io.getstream.services.Feed;
import io.getstream.models.*;
FeedsImpl feedsClient = new FeedsImpl(new StreamHTTPClient("<API key>", "<API secret>"));
// Create a feed with custom visibility
Feed feed = new Feed("user", "jack", feedsClient);
GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder()
.userID("jack")
.data(FeedInput.builder()
.visibility("public")
.build())
.build();
feed.getOrCreate(feedRequest);
// Create a feed group with default visibility
CreateFeedGroupRequest groupRequest = CreateFeedGroupRequest.builder()
.id("myid")
.defaultVisibility("public")
.activityProcessors(List.of(
ActivityProcessorConfig.builder().type("default").build()
))
.build();
CreateFeedGroupResponse groupResponse = feedsClient.createFeedGroup(groupRequest).execute().getData();
// Change visibility after feed creation
ChangeFeedVisibilityRequest visibilityRequest = ChangeFeedVisibilityRequest.builder()
.visibility("followers")
.build();
ChangeFeedVisibilityResponse visibilityResponse = feed.changeFeedVisibility(visibilityRequest).getData();Feed and Activity Visibility
Feed Visibility Levels
Feed groups have a default visibility (if it's not set when creating the group, visible will be set). You can also override the group's default when creating a feed. For changing a feed's visibility after creation, see Changing Feed Visibility.
The group default is applied when a feed is created, and each feed then stores its own visibility. Changing default_visibility on the group later does not rewrite the feeds that already exist, it only changes the level new feeds start at.
Visibility changes are asynchronous. The change request returns optimistically while follow relationships are reconciled in the background, and counts may be temporarily stale until reconciliation completes.
Supported visibility levels:
| Level | Viewing feed (activities + metadata) | Following | Posting |
|---|---|---|---|
visible | Anyone can view | Anyone can follow | Only the owner, feed_members and feed_moderators can post |
public | Anyone can view | Anyone can follow | Anyone can post |
followers | Only approved followers can view | Anyone can send a follow request, follow requests have to be approved | Only the owner, feed_members and feed_moderators can post |
members | Only members can view | Only members can follow | Only the owner, feed_members and feed_moderators can post |
private | Only the owner can view | Only the owner can follow | Only the owner can post |
Following a feed grants read access, not the ability to post. On every level except public, only the feed owner, its members and its moderators can add activities — a follower cannot post to a feed they do not own. To let someone contribute to a feed, add them as a member with a posting role; see the Membership levels guide.
Follower permission tiers
Every follow carries a role that decides what that follower can do. It defaults to feed_follower. There are two built-in follower roles, and out of the box neither lets a follower post into a feed they do not own, on any level except public, where anyone can post regardless:
| Role | Default on visible and followers |
|---|---|
feed_follower | Read the feed, comment, react and vote. Cannot post activities. |
feed_member_viewer | Read, react and vote. Cannot comment. |
A follow can also carry a custom role you created for your app, which is how you go beyond these two. See Custom follower roles below.
The role is assigned server-side, either when accepting a follow request or when updating an existing follow — see Follow and Unfollow. Client-side requests cannot set it.
You can also set a default for a whole feed group with default_follower_role, so every new follow of a feed in that group starts with the role you want and no per-follow call is needed. See Default follower role.
Those are defaults rather than fixed definitions. What each role may do is configurable per visibility level through the feed-visibility grants API, so the tiers you get are the ones you define. You could, for example, grant feed_follower the ability to post on visible feeds if your app wants an open wall. See the "Permissions and roles" guide for the grants API.
Two things to keep in mind. feed_member_viewer is also a member role, so changing its grants affects members carrying it, while feed_follower is follower-only.
And the two roles do not sit in a fixed order — which one is more permissive depends on the visibility level:
| Visibility | feed_member_viewer compared with feed_follower |
|---|---|
public, visible, followers | More restrictive — a subset of what feed_follower may do. |
members, private | Less restrictive for reading — it grants read access to the feed and its activities that feed_follower does not have. |
On members and private feeds a plain feed_follower can read only feeds they own, so following alone confers no access. Assigning feed_member_viewer to a follow on one of those feeds is therefore a deliberate way to give someone read-only access without making them a member — but it does widen their access, so do not treat follower_role as a restriction-only control.
Custom follower roles
A follow is not limited to the two built-ins. It can carry any custom role you have created for your app, which is what you reach for when neither built-in describes the tier you want.
The role is evaluated against exactly the grants you gave it for that visibility level. Nothing narrows it down to "follower-shaped" permissions, so if you grant your role add-activities on the visible visibility, followers carrying it can post to visible feeds. A shared wall where approved followers post, without making all of them members, is the motivating case.
Set it the same way as a built-in, server-side, on acceptFollow or updateFollow, or for a whole feed group at once with default_follower_role.
Two limits worth knowing:
- Reserved names are always rejected, including
feed_member,feed_moderator,admin,moderator,user,guest,anonymous, theglobal_*roles,server_side,*, and the chat and video roles. Creating a custom role with one of those names does not make it usable on a follow. - The grant belongs to the visibility level, not to the individual follow. A role holding
add-activitieson thevisiblevisibility can post to anyvisiblefeed in your app, not only the one you were thinking of. Scope it by which feeds you assign the role on.
If you delete a custom role while follows still name it, those follows fall back to feed_follower. They keep working, with follower-level access, rather than losing access entirely.
Activity Visibility Levels
public: marks the activity as public - everyone who can view feed content, can see itprivate: marks the activity as private - only feed owner can see ittag:mytag: marks the activity as only visible to followers/members with the permission to see this tag
This visibility system is very flexible and allows you to build:
- Apps like Patreon where only certain levels of users can see your content
- Apps like Strava where it's possible to share your activity with nobody, everyone or your followers
feed.addActivity({
type: "post",
text: "Premium content",
visibility: "tag",
visibility_tag: "premium",
});
// Premium users can see full activity, others a previewFor all the details on tag visibility read the Membership levels guide.