# Social Music App

This tutorial explains how to use Stream to build a scalable social network for music. In this example app, you can follow your friends, artists and playlists. We're going to support the following features:

- Timeline/News Feed

- Hashtags

- @mentions

- Likes & Comments

- Notification Feed

- Realtime Changes

#### Step 1: Setting Up The Feed Groups

First of all, we need to create feed groups for everything you can follow. For this app that will be: "user", "artist" and "playlist". Next, we'll need feeds to display the data. So we'll create the "timeline", "notification" and "tag" feeds groups. Take a moment to go to the [dashboard](https://getstream.io/dashboard/) and create these 6 feed groups. The "notification" feed group should be the "notification" feed type. The other 5 feed groups can be of the "flat" type.

#### Step 2: Follow Users, Artists and Playlists

The example below shows you how to follow users, artists and playlists.

<Tabs>

```python label="Python"
import stream

# Instantiate a new client
client = stream.connect('{{ api_key }}', '{{ api_secret }}', '65217')
timeline_chris = client.feed('timeline', 'chris')

# Follow a friend
timeline_chris.follow('user', 'jack')
# Follow a playlist
timeline_chris.follow('playlist', '90s_hits')
# Follow an artist
timeline_chris.follow('artist', 'coldplay')
```

</Tabs>

#### Step 3: Posting An Update

Let's dive straight into an example of how to add an activity:

<Tabs>

```python label="Python"
jack = client.feed("user", "jack")

# Jack posts an update with a hashtag and @mention
jack.add_activity({
 "actor": "jack",
 "verb": "post",
 "object": "post:10",
 "foreign_id": "post:10",
 "to": ["notification:chris", "tag:amsterdam"],
 "message": "Hi @chris, the coldplay concert was totally amazing #amsterdam"
})
```

</Tabs>

First of all, note how easy it is to add an activity. Certain fields like `actor` , `verb` and `object` are mandatory. `Message` is a custom field. You can add as many custom fields as you like. You can store numbers, strings, lists, and even objects.

The `TO` field is comparable to how CC works for email. For a production app, we recommend storing the activity in your database and syncing it to Stream.

#### Step 4: Likes & Comments

When a user likes an activity or writes a comment, you'll want to do two things:

- Notify the author of the original activity

- Show the like/comment to followers

The example below uses the `TO` support to write both to the `user:chris` and `notification:jack` feeds:

<Tabs>

```python label="Python"
# Chris likes Jack's post
chris = client.feed("user", "chris")
chris.add_activity({
 "actor": "chris",
 "verb": "like",
 "object": "post:10",
 "foreign_id": "like:25",
 "to": ["notification:jack"]
})
# Notify Jack and show it to Chris' followers (via the "chris" user feed)
```

</Tabs>

#### Step 5: Reading a Feed

It's easy to read a feed. You can use either  `offset`  or  `id_lt`  based pagination. For larger apps, we recommend filtering using  `id_lt`  as it performs much better.

<Tabs>

```python label="Python"
jack = client.feed('timeline', 'jack')

# Read the timeline for jack
activities = jack.get(limit=10)['results']
# Read the next page, use id filtering for optimal performance
next_activities = jack.get(limit=10, id_lt=activities[-1]['id'])['results']

# Reading a notification feed is very similar
chris = client.feed('notification', 'chris')
notifications = chris.get(limit=10)['results']
```

</Tabs>

The notification feed also includes the count of unseen and unread activities.

#### Step 6: Realtime Changes

Stream allows you to listen to feed changes in realtime. You can use either [websockets](/activity-feeds/docs/node/v2/realtime_backend/), [SQS queues](/activity-feeds/docs/node/v2/realtime_backend/#realtime-sqs/), or [Webhooks](/activity-feeds/docs/node/v2/realtime_backend/#realtime-webhooks/) to receive notifications. The following code creates a web socket connection to receive feed updates:

<Tabs>

```js label="JavaScript"
<script type="text/javascript">
  function failCallback(data) {
    alert('something went wrong, check the console logs');
    console.log(data);
  }

  const user1 = client.feed('user', '1', token);
  const subscription = user1.subscribe(function callback(data) {
    alert(data);
  }).then(null, failCallback);

  // The returned Subscription object has a method cancel
  // that will remove the listener from this channel
</script>
```

</Tabs>


---

This page was last updated at 2026-04-20T22:48:03.325Z.

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