Tracking Viewer Ratings of Twitch Stream Minute-by-Minute

This blog post shows how to use the Twitch API to retrieve the current number of viewers of a channel. See this page for an application example.

Get your API key

Although you can use the API without key, using the client_id is recommended to make sure you are to rate limited by Twitch. You can get the client_id by going to https://secure.twitch.tv/settings/connections and registering a new application:

twitch1.png

The client ID will automatically be generated for you:

twitch11.png

Calling the API response

You call the API with requests to

https://api.twitch.tv/kraken/streams/<CHANNEL>?client_id=<YOUR_CLIENT_ID>

For example, to get the information for channel manvsgame and client_id abcdef1234567890 you would request:

https://api.twitch.tv/kraken/streams/manvsgame?client_id=abcdef1234567890

If the channel is offline, the response will look like that:

{u'_links': {u'channel': u'https://api.twitch.tv/kraken/channels/manvsgame',
             u'self': u'https://api.twitch.tv/kraken/streams/manvsgame'},
 u'stream': None}

If the channel is online, the response will look like that:

{u'_links': {u'channel': u'https://api.twitch.tv/kraken/channels/manvsgame',
             u'self': u'https://api.twitch.tv/kraken/streams/manvsgame'},
 u'stream': {u'_id': 7797659104L,
             u'_links': {u'self': u'https://api.twitch.tv/kraken/streams/manvsgame'},
             u'channel': {u'_id': 8330235,
                          u'_links': {u'chat': u'https://api.twitch.tv/kraken/chat/manvsgame',
                                      u'commercial': u'https://api.twitch.tv/kraken/channels/manvsgame/commercial',
                                      u'editors': u'https://api.twitch.tv/kraken/channels/manvsgame/editors',
                                      u'features': u'https://api.twitch.tv/kraken/channels/manvsgame/features',
                                      u'follows': u'https://api.twitch.tv/kraken/channels/manvsgame/follows',
                                      u'self': u'https://api.twitch.tv/kraken/channels/manvsgame',
                                      u'stream_key': u'https://api.twitch.tv/kraken/channels/manvsgame/stream_key',
                                      u'subscriptions': u'https://api.twitch.tv/kraken/channels/manvsgame/subscriptions',
                                      u'teams': u'https://api.twitch.tv/kraken/channels/manvsgame/teams',
                                      u'videos': u'https://api.twitch.tv/kraken/channels/manvsgame/videos'},
                          u'abuse_reported': None,
                          u'background': u'http://static-cdn.jtvnw.net/jtv_user_pictures/manvsgame-background_image-10842e1c129df87d.png',
                          u'banner': None,
                          u'created_at': u'2009-09-17T19:42:52Z',
                          u'delay': 0,
                          u'display_name': u'MANvsGAME',
                          u'game': u'I Wanna Be The Guy',
                          u'logo': u'http://static-cdn.jtvnw.net/jtv_user_pictures/manvsgame-profile_image-731e0a1382912c9c-300x300.png',
                          u'mature': True,
                          u'name': u'manvsgame',
                          u'profile_banner': u'http://static-cdn.jtvnw.net/jtv_user_pictures/manvsgame-profile_banner-926ae0b81e5737df-480.png',
                          u'profile_banner_background_color': None,
                          u'status': u'MAN vs I WANNA BE THE GUY - I Wanna Be The Month!',
                          u'updated_at': u'2013-12-10T08:06:53Z',
                          u'url': u'http://www.twitch.tv/manvsgame',
                          u'video_banner': u'http://static-cdn.jtvnw.net/jtv_user_pictures/manvsgame-channel_offline_image-c01cba2e538ae8f5-640x360.jpeg',
                          u'views': 26903371},
             u'game': u'I Wanna Be The Guy',
             u'preview': {u'large': u'http://static-cdn.jtvnw.net/previews-ttv/live_user_manvsgame-640x400.jpg',
                          u'medium': u'http://static-cdn.jtvnw.net/previews-ttv/live_user_manvsgame-320x200.jpg',
                          u'small': u'http://static-cdn.jtvnw.net/previews-ttv/live_user_manvsgame-80x50.jpg',
                          u'template': u'http://static-cdn.jtvnw.net/previews-ttv/live_user_manvsgame-{width}x{height}.jpg'},
             u'viewers': 9233}}

The number of viewers is in ‘stream’ -> ‘viewers’ (e.g. 9233).

Example code

The following Python continuously calls the API and stores the number of viewers to a log file (make sure to add your client_id).

import requests
import json
from datetime import datetime, timedelta
import time
import logging
import argparse

BASE_URL = 'https://api.twitch.tv/kraken/'
CLIENTID = '<add your API key here>'

def start_logging(logfile='log.txt'):
    log = logging.getLogger()
    log.setLevel(logging.DEBUG)

    ch  = logging.StreamHandler()
    fh = logging.FileHandler(logfile)
    log.addHandler(ch)
    log.addHandler(fh)        

    requests_log = logging.getLogger("requests")
    requests_log.setLevel(logging.WARNING)

def get_viewers(stream_name):
    url = '{0}streams/{1}?client_id={2}'.format(BASE_URL, stream_name, CLIENTID)
    r = requests.get(url)
    if r.status_code != 200:
        raise Exception("API returned {0}".format(r.status_code))
    infos = r.json()
    stream = infos['stream']
    results = {}
    if not stream:
        results = {'online':False,'title':None,'viewers':0}
    else:
        viewers = stream['viewers']
        title = stream['channel']['status']
        results = {'online':True,'title':title,'viewers':viewers}

    results['time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    results['stream'] = stream_name
    return results

def constant_polling(stream, onint=1,offint=5):
    logging.info("starting polling, inteval is " + 
        "{0}min (online) and {1}min (offline)".format(onint, offint))
    while True:
        online = False
        try:
            res = get_viewers(stream)            
            online = res['online']
            txt = json.dumps(res) 
            logging.info("Streamviewercount: {0}".format(txt))
        except Exception as e:
            logging.warn("Polling failed: {0}".format(e))            

        sleep_interval = onint if online else offint
        time.sleep(60*sleep_interval)

if __name__=="__main__":
    parser = argparse.ArgumentParser(description='log viewer rating of twitch' +
        ' stream')
    parser.add_argument('channel', help='channel name')
    parser.add_argument('--int_on', help='interval if online (min)', default=1)
    parser.add_argument('--int_off', help='interval if offline (min)', default=5)
    args = parser.parse_args()
    start_logging()
    constant_polling(args.channel, args.int_on, args.int_off)

download GIST. Sample log file output:

starting polling, inteval is 1min (online) and 5min (offline)
Streamviewercount: {"stream": "dendi", "title": "time to practice !!!  !!!!!! Dendimon", "time": "2013-12-10 17:38:10", "viewers": 24978, "online": true}
Streamviewercount: {"stream": "dendi", "title": "time to practice !!!  !!!!!! Dendimon", "time": "2013-12-10 17:39:12", "viewers": 23199, "online": true}
Streamviewercount: {"stream": "dendi", "title": "time to practice !!!  !!!!!! Dendimon", "time": "2013-12-10 17:40:15", "viewers": 21841, "online": true}
Streamviewercount: {"stream": "dendi", "title": "time to practice !!!  !!!!!! Dendimon", "time": "2013-12-10 17:41:16", "viewers": 21247, "online": true}
Streamviewercount: {"stream": "dendi", "title": null, "time": "2013-12-10 17:42:19", "viewers": 0, "online": false}
comments powered by Disqus