# Instagram Tutorial

### Tutorial: Instagram Style Personalization

This tutorial will explain how to build Instagram style personalization using Stream. The underlying tech is similar to that of a Pinterest style feed, Etsy’s e-commerce recommendations, email digests (such as Quora) or YouTube’s content suggestions.

The goal of this tutorial is to build a feed similar to Instagram's 'Explore' feed. The content is based on what type of images you've engaged with in the past as well as graph analysis. For example, if you often click on snowboarding pictures it will learn that you like snowboarding and display related posts.

#### Step 1: Test Data

Let's get started. As a first step we'll want to insert test data.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Step 1: Setup the test data
const stream = require("getstream");
const request = require("request");

const API_KEY = process.env.STREAM_API_KEY;
const API_SECRET = process.env.STREAM_API_SECRET;

if (!API_KEY || !API_SECRET) {
  throw new Error("Expected STREAM_API_KEY, STREAM_API_SECRET env vars");
}

const client = stream.connect(API_KEY, API_SECRET);

// 1. Setup the test data
request.get("http://bit.ly/test-activities-gist", (error, response, body) => {
  if (error) {
    console.log(error);
  } else {
    const activities = JSON.parse(body);
    client.feed("user", "global").addActivities(activities);
  }
});
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Step 1: Setup the test data
import stream
import requests
client = stream.connect('{{ chat_api_key }}', '{{ api_secret }}')

activities = requests.get('http://bit.ly/test-activities-gist').json()
for activity in activities:
  activity_response = client.feed('user', 'global').add_activity(activity)
  print(activity_response)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# Step 1: Setup the test data
require 'stream'
require 'httparty'

client = Stream::Client.new('{{ chat_api_key }}', '{{ api_secret }}')
activities = JSON.parse(HTTParty.get('http://bit.ly/test-activities-gist'))
client.feed('user', 'global').add_activities(activities)
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Step 1: Setup the test data
$client = new GetStream\Stream\Client('{{ chat_api_key }}', '{{ api_secret }}');

$content = file_get_contents('http://bit.ly/test-activities-gist');
$activities = json_decode($content, true);

$response = $client->feed('user', 'global')->addActivities($activities);
echo json_encode($response) . "\n";
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
client, err := stream.New("{{ api_key }}", "{{ api_secret }}")
	if err != nil {
		panic(err)
	}

	// 1. Setup the test data
	resp, err := http.Get("http://bit.ly/test-activities-gist")
	if err != nil {
		panic(err)
	}
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var activities []stream.Activity
	err = json.Unmarshal(content, activities)
	if err != nil {
		panic(err)
	}

	feed, err := client.FlatFeed("user", "global")
	if err != nil {
		panic(err)
	}

	_, err := feed.AddActivities(context.TODO(), activities...)
	if err != nil {
		panic(err)
	}
```

</codetabs-item>

</codetabs>

If you run the above snippet you'll insert 3 activities with the following images and tags:

![snow](https://images.unsplash.com/photo-1483664852095-d6cc6870702d?auto=format&fit=crop&w=250&h=250&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%253D)

![beach](https://i.imgur.com/sJNn0vA.jpg)

![puppy](https://images.unsplash.com/photo-1510337550647-e84f83e341ca?auto=format&fit=crop&w=250&h=250&q=80&ixid=dW5zcGxhc2guY29tOzs7Ozs%253D)

#### Step 2: Analytics

For this tutorial we will only track clicks. If you're building a production application, you'll want to track any type of event that signals a user's interest. The example below shows how to perform the analytics tracking if a user clicks on the second image. Analytics tracking is normally done client-side, and in this case we are using the JS analytics client.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// set the current user
client.setUser({ id: 123, alias: "john" });
// track a click on the 2nd picture
var engagement = {
  // the label for the engagement, ie click, retweet etc.
  label: "click",
  // the ID of the content that the user clicked
  content: {
    foreign_id: "picture:2",
  },
  // score between 0 and 100 indicating the importance of this event
  // IE. a like is typically a more significant indicator than a click
  score: 15,
  // (optional) the position in a list of activities
  position: 2,
};

client.trackEngagement(engagement);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// track a click on the 2nd picture
client.analytics().trackEngagement(Engagement.builder()
    // set the current user
    .userData(new UserData("123", "john"))
    // the ID of the content that the user clicked
    .content(new Content("picture:2"))
    // the label for the engagement, ie click, retweet etc.
    .label("click")
    // score between 0 and 100 indicating the importance of this event
    // IE. a like is typically a more significant indicator than a click
    .boost(15)
    // (optional) the position in a list of activities
    .position(3)
    .build());
```

</codetabs-item>

</codetabs>

The example above uses a score of 15. The score is a number between 0 and 100 and indicates the importance of an event. A click is typically less important than a like or a share, so give those events a higher score.

#### Step 3: Understanding Features

Those clicks give us a hint that the user is interested in that activity. There are many features attached to a given activity. For this example, we'll take a look at the features attached to the 2nd activity:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Analyze which features activity with foreign ID picture:2 has
const params = { foreign_id: "picture:2" };
client.personalization.get("analyze_features", params).then(
  (resolution) => console.log(resolution["response"]["data"]),
  (rejection) => console.log(rejection),
);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Analyze which features activity with foreign id picture:2 has
features = client.personalization.get('analyze_features', foreign_id='picture:2')
print(features)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# Analyze which features activity with foreign id picture:2 has
features = client.personalization.get('analyze_features', foreign_id: 'picture:2')
puts features
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Analyze which features activity with foreign id picture:2 has
$features = $client->personalization()->get('analyze_features', ['foreign_id' => 'picture:2']);

print_r($features);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
client.personalization().get("analyze_features",ImmutableMap.of("foreign_id", "picture:2"));
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Analyze which features activity with foreign id picture:2 has
	resp, err := client.Personalization().Get(
		context.TODO(),
		"analyze_features",
		map[string]any{
			"foreign_id": "picture:2",
		},
	)
	if err != nil {
		panic(err)
	}
 fmt.Println(resp)
```

</codetabs-item>

</codetabs>

Once you've ran the code, ask yourself why the user is interested in this picture. Is it because the picture is about surfing? Or perhaps it indicates that he/she likes the post since it's created by a friend. One click doesn't give us significant data, but as the user keeps returning to your app, an interest profile starts to form.

#### Step 4: Follows

Personalization works best if you combine explicit follow relationships with analytics events. The example below shows how to create a follow relationship.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// John follows user conner3400
const john = client.feed("timeline", "john");
john.follow("user", "conner3400");
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# John follows user conner3400
client.feed('timeline', 'john').follow('user', 'conner3400')
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# John follows user conner3400
client.feed('timeline', 'john').follow('user', 'conner3400')
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// John follows user conner3400
$client->feed('timeline', 'john')->follow('user', 'conner3400');
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// John follows user conner3400
client.flatFeed("timeline", "john").follow(client.flatFeed("user", "conner3400"));
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// John follows user conner3400
	john, _ := client.FlatFeed("timeline", "john")
	conner, _ := client.FlatFeed("user", "conner3400")
	_, err := john.Follow(context.TODO(), conner)
	if err != nil {
		panic(err)
	}
```

</codetabs-item>

</codetabs>

#### Step 5: Reading the Personalized Feed

With both follows and analytics in place, we now have the ability to read the personalized feed.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
const params = {
  user_id: "john",
  feed_slug: "timeline",
};

client.personalization.get("personalized_feed", params).then(
  (resolution) => console.log(resolution["response"]["data"]),
  (rejection) => console.log(rejection),
);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
activities = client.personalization.get('personalized_feed', feed_slug='timeline', user_id='john')
print(activities)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
activities = client.personalization.get('personalized_feed', feed_slug: 'timeline', user_id: 'john')
puts activities
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$activities = $client->personalization()->get('personalized_feed', ['feed_slug' => 'timeline', 'user_id' => 'john']);

print_r($activities);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
client.personalization().get("personalized_feed", new ImmutableMap.Builder<string, object="">()
    .put("user_id", "john")
    .put("feed_slug", "timeline")
    .build());</string,>
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Reading the personalized feed
	resp, err := client.Personalization().Get(context.TODO(), "personalized_feed", map[string]any{
		"feed_slug": "timeline",
		"user_id":  "john",
	})
	if err != nil {
		panic(err)
	}
```

</codetabs-item>

</codetabs>

#### Step 6: Follow Suggestions

With the follow relationships in place, we have enough data to create follow suggestions.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
const params = {
  user_id: "john",
  source_feed_slug: "timeline",
  target_feed_slug: "user",
};

client.personalization.get("follow_recommendations", params).then(
  (resolution) => console.log(resolution["response"]["data"]),
  (rejection) => console.log(rejection),
);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
suggestions = client.personalization.get('follow_recommendations', target_feed_slug='user', user_id='john', source_feed_slug='timeline')
print(suggestions)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
suggestions = client.personalization.get('follow_recommendations', user_id: 'john', target_feed_slug: 'user', source_feed_slug: 'timeline')
puts suggestions
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$suggestions = $client->personalization()->get('follow_recommendations', [
  'user_id' => 'john',
  'source_feed_slug' => 'timeline',
  'target_feed_slug' => 'user',
]);

print_r($suggestions);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Map<string, object=""> suggestions = client.personalization().get("follow_recommendations", new ImmutableMap.Builder<string, object="">()
    .put("user_id", "john")
    .put("source_feed_slug", "timeline")
    .put("target_feed_slug", "user")
    .build()).get();</string,></string,>
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Follow suggestions
	resp, err := client.Personalization().Get(context.TODO(), "follow_recommendations", map[string]any{
		"user_id":     "john",
		"source_feed_slug": "timeline",
		"target_feed_slug": "user",
	})
	if err != nil {
		panic(err)
	}
```

</codetabs-item>

</codetabs>

This tutorial explained a simplified version of personalization for your app.

<admonition type="info">

These algorithms need to be customized for each enterprise customer. [Contact our data science team](https://getstream.io/contact/support/) to learn how personalization can enhance your app.

</admonition>


---

This page was last updated at 2026-04-17T17:33:25.297Z.

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