Introduction to Analytics

The Stream Analytics platform helps you understand how your users are engaging with your feed.

Feed quality, user's interests, and leading content producers are just a few examples of the insights that Analytics can provide. Implementing Analytics is a vital step towards improving engagement, conversion, and retention within your app.

This documentation will help you quickly set up the tracking that is required to power the platform.

Client Libraries

Client libraries are available for:

Stream also supports tracking interactions in emails via redirect links.

Event Types

We track two types of events:

Types of Engagements are unique to your app. Common examples include clicks, retweets, favorites, shares, etc.

Running into trouble during your integration? Feel free to reach out to support.

What to track

Track every event that you believe to be a good indicator of a user's interest in a piece of content. Here are some common examples:

  • Clicking on a link in an activity
  • Likes or comments on an activity
  • Sharing an activity to their followers
  • Viewing another user's profile page
  • Searching for a certain user/content/topic etc

What to track differs for every app - contact support if you have questions.

Installation & Setup

You're currently not logged in. Login so we can add your API key in the documentation snippets.


// Add this async loader code anywhere in your HTML code

<script type="text/javascript">
!function(t,e){t("StreamAnalytics","https://d2j1fszo1axgmp.cloudfront.net/2.6.0/stream-analytics.min.js",e)}(function(t,e,n){var s,i,r;n["_"+t]={},n[t]=function(e){n["_"+t].clients=n["_"+t].clients||{},n["_"+t].clients[e.apiKey]=this,this._config=e};var c=function(t){return function(){return this["_"+t]=this["_"+t]||[],this["_"+t].push(arguments),this}};s=["setUser","trackImpression","trackEngagement"];for(var a=0;a<s.length;a++){var o=s[a];n[t].prototype[o]=c(o)}i=document.createElement("script"),i.async=!0,i.src=e,r=document.getElementsByTagName("script")[0],r.parentNode.insertBefore(i,r)},this);
</script>
// the client is available via CocoaPods, just add this to you Podfile

pod 'stream-analytics-ios'
// download the latest release from here: https://github.com/GetStream/stream-analytics-android/releases/

Include the above code snippet in the <head></head> section of your page. Please note that the JavaScript is loaded asynchronously for optimal performance.

Using CommonJS modules

If you're using CommonJS modules, run the following command in your project directory:

npm install stream-analytics --save

After installing the package you can require it in your app:

var StreamAnalytics = require('stream-analytics');

Client setup

The snippet below shows you how to initialize Stream's analytics client:

var client = new StreamAnalytics({
  apiKey: "YOUR_API_KEY",
  token: "ANALYTICS_TOKEN"
});
// Initialize StreamAnalytics in AppDelegate

#import "AppDelegate.h"
#import "Stream.h"

@interface AppDelegate ()
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //enable debug logging
    [StreamAnalytics enableLogging:YES];
    return YES;
}
@end
// Import the library in your Gradle project:

dependencies {
  compile files('/path_to_file/stream-analytics-release-1.1.0.aar')
}

// Initialize the StreamAnalytics client
StreamAnalyticsAuth auth = new StreamAnalyticsAuth("YOUR_API_KEY","ANALYTICS_TOKEN");
StreamAnalytics client = StreamAnalyticsImpl.getInstance(auth);

Add your credentials to your project Info.plist file:


      <dict>
      <key>APIKey</key>
      <string></string>
      <key>JWTToken</key>
      <string></string>
      </dict>
    

Bind the service in your application's manifest.xml:


        <uses-permission android:name="android.permission.INTERNET" />
      

You must always specify the current user before sending events:

// user id and a friendly alias for easier to read reports
client.setUser({id: 486892, alias: 'Julian'});
#import "Stream.h"


// set user id only 
[[StreamAnalytics sharedInstance] setUserId:@"486892"];

// add friendly alias for the user
[[StreamAnalytics sharedInstance] setUserId:@"486892" andAlias:@"Julian"];
// set user data
client.setUser("486892", "Eric");

// you can also set the userId only
// client.setUserId("486892");

Tracking Engagements

The snippet below shows an example of how to track engagements. Common examples include likes, comments, profile views, and link clicks.

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': 'tweet:34349698'
  },
  // (optional) the position in a list of activities
  'position': 3,
  // (optional) boost, default is 1. 
  'boost': 2,
  // (optional) the feed the user is looking at
  'feed_id': 'user:thierry',
  // (optional) the location in your app. ie email, profile page etc
  'location': 'profile_page'
};

client.trackEngagement(engagement);
StreamEngagement *event = [StreamEngagement createEngagementEvent:@"click" withContent: @{@"foreign_id":@"message:34349698"}.mutableCopy]];

event.position = @"3";
event.boost = @2;
event.feedId = @"user:thierry";
event.location = @"profile_page";

[[StreamAnalytics sharedInstance] send:event];
client.send(new Engagement.EventBuilder()
    .withFeedId("user:thierry")
    .withContent(
        new Content.ContentBuilder()
            .withForeignId("message:34349698")
            .withAttribute("verb", "share")
            .withAttribute("actor", new ContentAttribute("1", "user1"))
            .build()
        )
    .withBoost(2)
    .withLocation("profile_page")
    .withPosition("3")                
    .build()
);

Parameters

Name Type Description Optional
label string The type of event, ie click, share, search.
content string or object The content that the engagement relates to, either as an ID or content object
position string The position in a list of activities, starting at 0.
boost string The boost factor allows you to indicate this engagment is more important. Specifying 2 here means the engagement is twice as important as other engagements with the same label.
feed_id string The feed the user is looking at.
location string The location in your app. ie email, homepage, profile page etc.

Tracking Impressions

The next step is to track which activities are shown to the user.

The code snippet below shows you how to track that the user viewed 3 tweets:

var impression = {
  // the list of content IDs displayed to the user
  'content_list': ['tweet:34349698', 'tweet:34349699', 'tweet:34349697'],
  // (optional) the feed where this content is coming from
  'feed_id': 'flat:tommaso',
  // (optional) the location in your app. ie email, profile page etc
  'location': 'profile_page'
};

// send the impression events
client.trackImpression(impression);
//track an impression
StreamImpression *event = [StreamImpression createImpressionEventWithContentList:@[@"song:34349698", @"song:34349699", @"song:34349697"]];

// (optional) the feed where this content is coming from
event.feedId = @"flat:tommaso";
// (optional) the location in your app. ie email, profile page etc
event.location = @"ios-app";

// send the impression events
[[StreamAnalytics sharedInstance] send:event];
client.send(new Impression.EventBuilder()
    .withContentList(
        new Content.ContentBuilder()
            .withForeignId("tweet:34349698")
            .withAttribute("verb", "share")
            .withAttribute("actor", new ContentAttribute("1", "user1"))
            .build(),
        new Content.ContentBuilder()
            .withForeignId("tweet:34349699")
            .build(),
        new Content.ContentBuilder()
            .withForeignId("tweet:34349610")
            .build()
    )
    .withFeedId("flat:tommaso")
    .withLocation("android-app")
    .build()
);

Note: There are two ways to specify the value for content_list. The example above uses a list of ids.

Alternatively, you can pass a list of objects as shown below:


    'content_list': [
      {'foreign_id': 'tweet:34349698', 'message': 'Hi'},
      {'foreign_id': 'tweet:34349699', 'message': 'Hello'},
      {'foreign_id': 'tweet:34349697', 'message': 'Ciao'}
    ]
  

The foreign_id field is required. This syntax allows you to add more information about the content you are tracking.

If your feeds are powered by Stream, be sure to use the same foreign ids as used in your feed integration. This way the information is picked up automatically.

Parameters

Name Type Description Optional
content_list list of strings or objects The list of content the user is looking at. Either a list of IDs or objects.
feed_id string The feed the user is looking at.
location string The location in your app. ie email, homepage, profile page etc.

Email tracking

It's important to track how users interact with your email.

Many of your less active users will only interact with your emails, and rarely visit your app. Tracking email interactions is important to improve the experience of these users.

Tracking clicks in emails works via redirects. You can use our client libraries to generate a redirect link.

Note: you can only create redirect links from your server-side application using one of the API clients. Please refer to our API documentation if you need any information on how to obtain one of the clients.

Example

# the url to redirect to
target_url = 'http://mysite.com/detail'

# track the impressions and a click
impression = {
    'content_list': ['tweet:1', 'tweet:2', 'tweet:3'], 
    'user_data': 'tommaso', 
    'location': 'email',
    'feed_id': 'user:global'
}

engagement = {
    'content': 'tweet:2', 
    'label': 'click',
    'position': 1, 
    'user_data': 'tommaso', 
    'location': 'email',
    'feed_id': 
    'user:global'
}

events = [impression, engagement]
tracking_url = client.create_redirect_url(target_url, user_id, events)

# when the user opens the tracking url in their browser gets redirected to the target url
# the events are added to our analytics platform
$client = new Client(
    'YOUR_API_KEY',
    'API_KEY_SECRET'
);

# the url to redirect to
$targetUrl = 'http://my.application.com/page/';

$impression = [
  'content_list' => ['tweet:34349698', 'tweet:34349699', 'tweet:34349697'],
  'feed_id'      => 'flat:tommaso',
  'location'     => 'profile_page',
  'user_data'    => ['id' => 'bubbles'],
  'label'        => 'impression'
];

$engagement = [
  'content'      => 'tweet:34349698',
  'feed_id'      => 'flat:tommaso',
  'location'     => 'profile_page',
  'user_data'    => ['id' => 'frank'],
  'label'        => 'click'
];

$events = [$impression, $engagement];
$trackingUrl = $client->createRedirectUrl($targetUrl, $events);

# when the user opens the tracking url in their browser gets redirected to the target url
# the events are added to our analytics platform

When a user clicks the tracking URL, they are re-directed to the specified target URL. During the re-direct, Stream tracks the impression and engagement events you specified.

Adding Meta Data

The more meta data Stream has about your content, the more effective Analytics and Personalization become. This section will show you how to add rich meta data to your events.

Note: if you are tracking impressions and engagements on activities stored in Stream, we will automatically pick up the meta data and you don't need to specify it when tracking events.

The example below shows you how to attach meta data to your engagement:

var engagement = {
  'label': 'click',
  'content': {
    'foreign_id': 'post:42',
    'label': 'Tom shared She wolf from Shakira',
    'actor': {
        'id': 'user:2353540',
        'label': 'Tom'
    },
    'verb': 'share',
    'object': {
        'id': 'song:34349698',
        'label': 'She wolf'
    },
    'genre': 'latin-pop'
  },
  'feed_id': 'timeline:tom'
};
client.trackEngagement(engagement);
NSMutableDictionary *content = [NSMutableDictionary new];
content[@"foreign_id"] = @"post:42";
content[@"label"] = @"Tom shared She wolf from Shakira";
content[@"actor"] = @{@"id": @"user:2353540", @"label": @"Tom"};
content[@"object"] = @{@"id": @"song:34349698", @"label": @"She wolf"};
content[@"verb"] = @"share";
StreamEngagement *event = [StreamEngagement createEngagementEvent:@"click" withContent: content];
event.feedId = @"timeline:tom";
[[StreamAnalytics sharedInstance] send:event];
client.send(new Engagement.EventBuilder()
    .withFeedId("user:ChartMill")
    .withLabel("click")
    .withContent(
        new Content.ContentBuilder().withForeignId("message:34349698").build()
    )
    .withFeatures(new Feature("topic", "politics"))
    .build()
);

Notice the label field. When you specify the label field, Analytics will use this in place of an ugly id. Using labels makes the interface much easier to use.

Actor, Verb, Object

The actor, verb and object fields are the basic fields describing an activity. If your user is clicking on an activity you'll definitely want to add those fields.

Tracking meta data for impressions works the same way. The only difference is that you're passing a list of content objects:

var impression = {
  'content_list': [
    {
      'foreign_id': 'post:42',
      'actor': {'id': 'user:2353540'},
      'verb': 'share',
      'object': {'id': 'song:34349698'},
    }
  ],
  'feed_id': 'timeline:tom'
};

client.trackImpression(impression);
NSMutableDictionary *content = [NSMutableDictionary new];
content[@"foreign_id"] = @"post:42";
content[@"label"] = @"Tom shared She wolf from Shakira";
content[@"actor"] = @{@"id": @"user:2353540", @"label": @"Tom"};
content[@"object"] = @{@"id": @"song:34349698", @"label": @"She wolf"};
content[@"verb"] = @"share";

StreamEngagement *event = [StreamImpression createImpressionEventWithContentList:@[content]];
event.feedId = @"timeline:tom";

[[StreamAnalytics sharedInstance] send:event];
client.send(new Impression.EventBuilder()
    .withFeedId("user:ChartMill")
    .withLabel("click")
    .withContentList(
        new Content.ContentBuilder().withForeignId("message:34349698").build()
    )
    .withFeatures(new Feature("topic", "politics"))
    .build()
);

Personalization & Analytics

Personalization

Stream makes it easy to add personalized feeds to your application. You can setup personalized feeds by implementing our analytics platform and reaching out to our data science and sales team.

As your users interact with your application, Stream starts to understand what they are interested in. You can use these insights to do a whole lot of awesome:

  • Personalize Feeds
  • Create Follow Suggestions
  • Optimize Emails
  • Product Recommendations
  • Content Recommendations

This is our most advanced feed technology to date. It enables you to substantially improve the engagement, conversion and retention within your app.

Learn more about Personalization.

Analytics

The Stream Analytics platform helps you understand how your users are engaging with your feed.

Quickly glean insights on:

  • Feed Quality
  • Users & Interests
  • Content Producers

Analytics provides specialized reporting that goes far beyond pageviews - feed-specific insights you won't get from GA or Mixpanel.

Learn more about Analytics.

In-Depth Documentation

Documentation for Personalization & Analytics.

Setting up personalized feeds

Before setting up personalized feeds you need to integrate both Stream's analytics and feed APIs. After that contact our data science team to discuss how to best approach personalization for your app. The best personalization algorithms are different for every app. Our team will work with you and continously help optimize the results. Note that personalized feeds are only available on enterprise plans.

Meta

Certain objects such as user profiles, product details etc. aren't part of the feeds. They can however be useful for personalization. To sync this data to Stream you can use the META endpoint. This endpoint is optimized for batch writes. The example below shows you how to create, update and delete records. Note that the META endpoint is only available to select Enterprise plans.

// auth details
var jwt = require('jsonwebtoken'),
    request = require('request');
var url = 'https://yourcompany.getstream.io/yourcompany/meta/';
var permissions = {
    'user_id': '*',
    'resource': '*',
    'action': '*',
}
var token = jwt.sign(permissions, STREAM_API_SECRET, { algorithm: 'HS256', noTimestamp: true })

// create or update the meta data
var meta = {
    'user:1': {'name': 'Kevin', 'interests': ['machine-learning', 'python']}, 
    'user:2': {'name': 'Thierry', 'interests': ['python', 'scalability']},
    'product:1': {'name': 'Iphone 7', 'brand': 'Apple'}
}
var data  = {'data': meta}
request({
    url: url,
    qs: {'api_key': STREAM_API_KEY},
    method: "POST",
    json: data,
    headers: {
      'authorization': token,
      'stream-auth-type': 'jwt'
    }
}, function(error, response, body) {

    if (error || response.statusCode != 200) {
        console.log('Error reading the feed', body);
        return callback(error || body);
    }
    console.log(body)
})

// remove user:1
var meta = {'user:1': undefined, 'user:2': undefined}
var data  = {'data': meta}
request({
    url: url,
    qs: {'api_key': STREAM_API_KEY},
    method: "POST",
    json: data,
    headers: {
      'authorization': token,
      'stream-auth-type': 'jwt'
    }
}, function(error, response, body) {

    if (error || response.statusCode != 200) {
        console.log('Error reading the feed', body);
        return callback(error || body);
    }
    console.log(body)
})

Reading personalized feeds

You can read personalized feeds on your own custom getstream.io endpoint. The example below shows you how to use JWT auth to read a personalized feed.

// auth details
var jwt = require('jsonwebtoken'),
    request = require('request');
var permissions = {
    'user_id': '*',
    'resource': '*',
    'action': '*',
}
var token = jwt.sign(permissions, STREAM_API_SECRET, { algorithm: 'HS256', noTimestamp: true })

var userId = 123
var url = 'https://yourcompany.getstream.io/yourcompany/personalized_feed/' + userId + '/';

request({
    url: url,
    qs: {'api_key': STREAM_API_KEY},
    method: "POST",
    json: true,
    headers: {
      'authorization': token,
      'stream-auth-type': 'jwt'
    }
}, function(error, response, body) {

    if (error || response.statusCode != 200) {
        console.log('Error reading the feed', body);
        return callback(error || body);
    }
    console.log(body)
})