Membership levels

Membership levels let you create different tiers among a feed's audience, and control which activities are available to which users. This gives users the option to post content that only premium members can see.

This page details how you can set up membership levels.

Create membership levels

Use server-side SDKs to create membership levels. You can define unified membership levels for your application, or scope them (for example, to specific users) using custom data.

premiumResponse, err := feedsClient.CreateMembershipLevel(context.Background(), &getstream.CreateMembershipLevelRequest{
  ID:          "premium",
  Name:        "Premium",
  Description: getstream.PtrTo("Weekly QA with me"),
  Custom: getstream.PtrTo(map[string]any{
    // Lets you query membership levels by creator.id, useful if you want to scope membership levels to users
    "creator_id": "creator_123",
  }),
  // Lets you sort membership levels by priority
  Priority: getstream.PtrTo(100),
  // Users with this membership level can see activities with these tags
  Tags:     getstream.PtrTo([]string{"premium"}),
})
if err != nil {
  log.Fatal("Error creating Premium membership level:", err)
}
log.Printf("Created Premium membership level: %+v", premiumResponse.Data.MembershipLevel)

innerCircleResponse, err := feedsClient.CreateMembershipLevel(context.Background(), &getstream.CreateMembershipLevelRequest{
  ID:          "inner-circle",
  Name:        "Inner Circle",
  Description: getstream.PtrTo("You can see new videos a week earlier, and weekly QA with me"),
  Custom: getstream.PtrTo(map[string]any{
    "creator_id": "creator_123",
  }),
  Priority: getstream.PtrTo(200),
  // Users in this membership level can see premium and inner circle content as well
  Tags:     getstream.PtrTo([]string{"premium", "inner-circle"}),
})
if err != nil {
  log.Fatal("Error creating Inner Circle membership level:", err)
}
log.Printf("Created Inner Circle membership level: %+v", innerCircleResponse.Data.MembershipLevel)

Overview of the membership level model

MembershipLevelResponse

NameTypeDescriptionConstraints
created_atnumberWhen the membership level was createdRequired
customobjectCustom data for the membership level-
descriptionstringDescription of the membership level-
idstringUnique identifier for the membership levelRequired
namestringDisplay name for the membership levelRequired
priorityintegerPriority levelRequired
tagsstring[]Activity tags this membership level gives access toRequired
updated_atnumberWhen the membership level was last updatedRequired

Assign membership level to users

To assign a membership level to a user, you need to add them as a feed member, and set their membership level.

Info:

Users still have to follow the feed to see posts in their timelines. Membership levels are only used for authorization purposes.

_, err = feedsClient.UpdateFeedMembers(context.Background(), "creator", "creator-feed-id", &getstream.UpdateFeedMembersRequest{
  Operation: "upsert",
  Members: getstream.PtrTo([]getstream.FeedMemberRequest{
    {
      UserID:           "premium-fan-id",
      MembershipLevel:  getstream.PtrTo("premium-membership-level-id"),
      Role:             getstream.PtrTo("feed_member_viewer"),
    },
  }),
})
if err != nil {
  log.Fatal("Error updating feed members:", err)
}

fmt.Println("Feed members updated successfully!")

Create a premium activity

response, err := client.Feeds().AddActivity(context.Background(), &getstream.AddActivityRequest{
    Feeds:         []string{"user:alice"},
    Type:          "post",
    Text:          getstream.PtrTo("Premium content"),
    Visibility:    getstream.PtrTo("tag"),
    VisibilityTag: getstream.PtrTo("premium"),
    UserID:        getstream.PtrTo("alice"),
})
if err != nil {
    log.Fatal("Error adding activity:", err)
}

log.Printf("Activity added successfully: %+v", response)
// Premium users can see full activity, others a preview

Users who don't have access to the post will only see a preview:

  • No attachments are shown
  • The activity text is truncated (first 20 characters are shown, for example: "Behind the scenes of...")

The activity.preview flag is true if a user received only a preview of the activity, not the full content.

Query membership levels

response, err := client.Feeds().QueryMembershipLevels(context.Background(), &getstream.QueryMembershipLevelsRequest{
  Filter: getstream.PtrTo(map[string]any{
    "custom": map[string]any{
      "$contains": map[string]any{
        "creator_id": creatorID,
      },
    },
  }),
  Sort: getstream.PtrTo([]getstream.SortParamRequest{
    {
      Field:     getstream.PtrTo("priority"),
      Direction: getstream.PtrTo(-1),
    },
  }),
})
if err != nil {
  log.Fatal("Error querying membership levels:", err)
}

fmt.Printf("Found %d membership levels:\n", len(response.Data.MembershipLevels))

Filter options

name type description supported operations example
id string or list of strings The ID of the membership level $in, $eq { id: { $in: [ 'abc', 'xyz' ] } }
name string or list of strings The name of the membership level $in, $eq { name: { $in: [ 'abc', 'xyz' ] } }
description string or list of strings The description of the membership level $in, $eq { description: { $in: [ 'abc', 'xyz' ] } }
priority number The priority of the membership level $eq, $gt, $lt, $gte, $lte { priority: { $gte: 100 } }
tags list of strings Tags the membership level grants access to $eq, $in, $contains { tags: { $in: [ 'premium', 'inner-circle' ] } }
custom object Custom data of the membership level $contains, $path_exists { custom: { $contains: {creator_id: '123' } } }
created_at string, must be formatted as an RFC3339 timestamp The time the membership level was created $eq, $gt, $lt, $gte, $lte { created_at: { $gte: '2023-12-04T09:30:20.45Z' } }
updated_at string, must be formatted as an RFC3339 timestamp The time the membership level was last updated $eq, $gt, $lt, $gte, $lte { updated_at: { $gte: '2023-12-04T09:30:20.45Z' } }

Sort options

Fields:

  • priority
  • created_at
  • updated_at

Direction: 1 or -1

Update membership levels

updateRequest := &getstream.UpdateMembershipLevelRequest{
  Name:        getstream.PtrTo("Premium"),
  Description: getstream.PtrTo("Weekly QA with me"),
  Custom:      getstream.PtrTo(customData),
  Priority:    getstream.PtrTo(100),
  Tags:        getstream.PtrTo([]string{"premium"}),
}

response, err := feedsClient.UpdateMembershipLevel(context.Background(), premiumMembershipLevelID, updateRequest)

if err != nil {
  log.Fatal("Error updating membership level:", err)
}

log.Printf("Successfully updated membership level: %+v\n", response.Data.MembershipLevel)

Delete membership level

response, err := feedsClient.DeleteMembershipLevel(ctx, premiumMembershipLevelID, &getstream.DeleteMembershipLevelRequest{})
if err != nil {
  log.Fatal("Error deleting membership level:", err)
}
Add Chat to my app: getstream.io/SKILL.md

The fastest way to build with Stream. Start a new project or improve an existing one. Full CLI and documentation integration out of the box.


Ask your agent:

/stream Build me a Social App with Feeds and Moderation.
/stream Any livestream calls running?
/stream Feeds Go v3: <Your Question>