Streams

Stream endpoints

Seven metric sets describe a single broadcast. Every single-stream endpoint costs 1 credit per request — standard, extra, all stream games, paid subscribers, chat analytics, and the full chat log. The exception is the 5-minute interval series, which returns the whole broadcast as a time series for 3 credits. Narrow any stream to part of its runtime with an exact-time time window.

YouTube uses channel IDs

For YouTube, pass the channel ID in the path, e.g. /channels/UCWsDFcIhY2DBi3GB5uykGXA/streams-extra/10203361939495629149/chat?platform=youtube.

Standard stats

Performance metrics for one specific broadcast. Available on all active platforms.

GET /api/v2/channels/{name}/streams/{stream-id}?platform={platform}
Set of metricsAvailabilityCost / request
StandardAll platforms1
RESPONSEJSON
{ "data": { "platform": "twitch", "channel_name": "shroud", "channel_display_name": "shroud", "channel_id": "37402112", "avatar_url": "https://static-cdn.jtvnw.net/.../300x300.png", "stream_id": "41976921163", "stream_status": "making my sorc NOW also check out !announcement", "stream_start": "2023-03-18 19:05:30", "stream_end": "2023-03-19 03:35:00", "stream_language": "en", "hours_watched": 115906, "airtime_in_m": 515, "peak_viewers": 17819, "average_viewers": 13504, "followers_gain": 676, "top_game_by_hw": "Diablo IV", "top_game_by_hw_%": 81.7 } }

Field availability by platform

Platform(s)Fields not returned
NimoTV, Bigo LIVE, Nonolive, SOOP Korea, CHZZK, SOOP, SteamTVfollowers_gain
Rumblefollowers_gain, top_game_by_hw, top_game_by_hw_%

Supported time periods

Slice a broadcast down to specific hours or minutes with time=YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM to get statistics for only part of the stream.

Extra metrics TWITCH

Standard stream metrics plus an extra_metrics object with authorized-viewer and retention signals. Twitch only.

GET /api/v2/channels/{name}/streams-extra/{stream-id}?platform=twitch
Set of metricsAvailabilityCost / request
ExtraTwitch only1
RESPONSE · extra_metricsJSON
// standard fields, then: "extra_metrics": { "live_views": 464087, "unique_viewers": 176871, "unique_auth_viewers": 147068, "peak_auth_viewers": 13674, "auth_viewers_average_view_duration_in_m": 43, "authorized_to_all_viewers_ratio_%": 83, "viewers_from_last_stream_%": 69.4, "returned_viewers_%": 35.3, "estimated_audience": 166405, "estimated_audience_average_view_duration_in_m": 42 }

From April 3 2023, Authorized and Unique Viewers are collected only for channels authorized on Streams Charts via Twitch — and only for the period a channel has been authorized. A broadcast from before that returns null for these fields however large the channel.

Under an exact-time window

live_views is always null when you pass a minute-level time window — it is measured once per broadcast, not over an arbitrary slice of it. The authorized-viewer fields are recalculated for the window. stream_start and stream_end always report the real edges of the broadcast, never the edges of the window you asked for.

All stream games NEW

Standard stream metrics plus an all_stream_games array breaking the broadcast down by every game played — each with its own viewership, airtime, and followers gain. Available on all active platforms.

GET /api/v2/channels/{name}/streams-extra/{stream-id}/games?platform={platform}
Set of metricsAvailabilityCost / request
Standard + all stream gamesAll platforms1
RESPONSE · all_stream_gamesJSON
// standard fields, then: "all_stream_games": [ { "name": "Rocket League", "hours_watched": 161731, "peak_viewers": 64933, "average_viewers": 41293, "airtime_in_m": "235", "followers_gain": "3044" }, { "name": "Just Chatting", "hours_watched": 35980, "peak_viewers": 50507, "average_viewers": 39250, "airtime_in_m": "55", "followers_gain": "918" } ]

5-minute intervals NEW

One broadcast as a time series: a point every 5 minutes carrying concurrent viewers, authorized viewers, followers gained, and the game and title live at that moment — plus chat and subscriber activity per point on request. Available on all active platforms. This is the only stream endpoint that is not 1 credit: 3 credits per call, however long the broadcast.

GET /api/v2/channels/{name}/streams-extra/{stream-id}/intervals?platform={platform}
Set of metricsAvailabilityCost / request
Interval seriesAll platforms3
Series + subscriber metricsTwitch only4
Series + chat metricstwitch, kick, youtube5
Series + chat + subscriber metricsTwitch only6

The interval is fixed at 5 minutes — the resolution the data is stored at. There is no interval parameter: anything finer resolves to the same bucket, and anything coarser is a downsample you can do on your side from one response.

Parameters

ParameterTypeDescription
platformstringRequired, as on every stream endpoint.
chat_metricsbooleantrue adds a chat block to every point. Adds 2 credits.
subs_metricsbooleantrue adds a subs block to every point. Adds 1 credit.
timestringExact-time window YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM — returns only the points inside it. Does not change the price.
REQUESTCURL
curl -X GET "https://streamscharts.com/api/v2/channels/caedrel/streams-extra/317700373731/intervals?platform=twitch" \ -H 'Client-ID: XXXXXXXXXXXX' -H 'Token: YYYYYYYYYYYYYY'
RESPONSEJSON
{ "data": [ { "time": "2026-09-07 08:40:00", "viewers": 7441, "auth_viewers": 4482, "followers_gain": 0, "followers_gain_total": 0, "games": ["League of Legends"], "stream_status": "🔴LPL BLG VS AL UPPER BRACKET PLAYOFFS🔴" }, { "time": "2026-09-07 08:45:00", "viewers": 11061, "auth_viewers": 8561, "followers_gain": 1, "followers_gain_total": 1, "games": ["League of Legends"], "stream_status": "🔴LPL BLG VS AL UPPER BRACKET PLAYOFFS🔴" } ], "meta": { "platform": "twitch", "channel_name": "caedrel", "stream_id": "317700373731", "stream_start": "2026-09-07 08:36:45", "stream_end": "2026-09-07 11:30:00", "interval_in_m": 5, "points": 36, "average_viewers": 31595, "channel_average_viewers_30d": 47706 } }

The data array above is trimmed to two of this broadcast's 36 points; a full response holds them all, oldest first. Everything constant for the broadcast or the channel sits in meta once, not on every point. Text arrives JSON-escaped: emoji and other non-ASCII characters in stream_status come back as \uXXXX sequences, which any JSON parser decodes back to the original title.

RESPONSE · chat_metrics=true&subs_metrics=trueJSON
{ "time": "2026-09-07 11:25:00", "viewers": 42552, "auth_viewers": 34849, "followers_gain": 7, "followers_gain_total": 149, "games": ["League of Legends"], "stream_status": "🔴LPL BLG VS AL UPPER BRACKET PLAYOFFS🔴", "chat": { "total_messages": 647, "active_chatters": 362, "bits_spent": 1 }, "subs": { "subs_gain": 0, "min_income_from_subs_in_$": 184, "max_income_from_subs_in_$": 326 } }

Point fields

FieldTypeDescription
timestringStart of the 5-minute bucket, UTC, YYYY-MM-DD HH:MM:SS — the same format as stream_start.
viewersintegerConcurrent viewers at that moment.
auth_viewersinteger | nullAuthorized viewers. Twitch only, and only for channels authorized on Streams Charts — null otherwise, and for the period before a channel authorized.
followers_gaininteger | nullNet follower change over those 5 minutes. Can be negative — it is a net change, not a gain. null on platforms that do not report followers.
followers_gain_totalinteger | nullNet follower change accumulated from the start of the broadcast to this point.
gamesarrayThe game live at that moment. Game data is stored in the same 5-minute slots, so in practice this is one element; the array shape is kept for forward compatibility.
stream_statusstringThe title as the streamer set it at that moment — emoji, case and punctuation untouched.
chat.total_messagesintegerMessages in those 5 minutes. Only with chat_metrics=true.
chat.active_chattersintegerChatters who wrote at least once in those 5 minutes.
chat.bits_spentinteger | nullBits cheered in those 5 minutes. Twitch only — null on Kick and YouTube.
subs.subs_gainintegerNew subscriptions in those 5 minutes. Only with subs_metrics=true.
subs.min_income_from_subs_in_$integerLower bound of estimated subscription income, accumulated from the start of the broadcast.
subs.max_income_from_subs_in_$integerUpper bound of the same estimate.

Two fields are cumulative — followers_gain_total and the two subs income bounds. Everything else is the value for that 5-minute bucket alone.

Meta fields

FieldTypeDescription
stream_startstringReal start of the broadcast, to the second.
stream_endstringReal end of the broadcast. On a stream that is still live, this is the last closed bucket — how far the data runs, not the end of the broadcast.
interval_in_mintegerAlways 5. Read it instead of hard-coding the step.
pointsintegerNumber of points in data.
average_viewersintegerAverage concurrent viewers over the whole broadcast.
channel_average_viewers_30dintegerThe channel's average concurrent viewers over the last 30 days, for context.

Field availability by platform

Platform(s)Fields not returned
NimoTV, Bigo LIVE, Nonolive, SOOP Korea, CHZZK, SOOP, SteamTV, Rumblefollowers_gain, followers_gain_total
Every platform except Twitchauth_viewers, the subs block, chat.bits_spent
Every platform except Twitch, Kick and YouTubethe chat block
Asking for a block a stream does not have is not charged

If you pass chat_metrics=true or subs_metrics=true for a stream whose platform or channel has no such data, the surcharge is not applied and the block comes back as null. So chat_metrics=true on a stream without chat coverage costs 3 credits, not 5. x-credits-charged always reports what was actually taken — 3, 4, 5 or 6.

Narrowing to a window

Pass an exact-time window to get part of the broadcast: time=2026-09-07 09:00,2026-09-07 09:30. The price does not change — a window costs the same 3 credits as the whole stream.

RuleBehaviour
Window edgesStart inclusive, end exclusive — 09:00,09:30 returns 6 points, 09:00 through 09:25.
Edges off the 5-minute gridPulled inward: 09:07,09:23 returns 09:10, 09:15 and 09:20 — the partly covered bucket at each edge is dropped.
Window wider than the broadcastClipped to the broadcast; you get every point and nothing empty around it.
Window outside the broadcast404 not_found, not charged — probing for coverage costs nothing.
End before or equal to start422 invalid_parameter — time window end must be after start, not charged.
Slice a broadcast only with the exact-time form of `time`

time must carry hours and minutes on both sides. Plain dates are not rejected here, but they are shifted a day: the end date is pushed back 24 hours, so time=2026-09-07,2026-09-09 returns the 7th while time=2026-09-07,2026-09-08 is an empty window and answers 422. The presets such as 7-days or today are ignored and return the whole broadcast at the same price. To slice a stream, always pass YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM.

Reading the series

  • Offline gaps are missing points, not zeros. If the broadcast dropped, those minutes have no row at all — no null points, no zero viewers.
  • The first point can be earlier than stream_start. stream_start is second-precise; the first point is the bucket containing it, so a stream starting at 08:36:45 opens the series at 08:35:00.
  • The last bucket is usually partial. A stream ending mid-bucket leaves a final point holding only a few minutes of data — low counts there are the truncated tail, not an anomaly.
  • Rumble's grid is sparser than 5 minutes. Its collection leaves gaps of 5, 10, 15 or more minutes between points, so read time on each point rather than assuming a fixed step.
  • No derived chat metrics per point. passive_chatters and chat_engagement_rate_% are not returned here — the denominator is not meaningful over 5 minutes. Take them from chat analytics for the whole broadcast.
  • No pagination. A 24-hour broadcast is 288 points and comes back in one response.

Paid subscribers TWITCH

Subscriber activity for one broadcast — new vs. returning subs, tiers, and estimated income. Twitch only.

GET /api/v2/channels/{name}/streams-extra/{stream-id}/subs?platform=twitch
Set of metricsAvailabilityCost / request
Paid subscribersTwitch only1
RESPONSEJSON
{ "data": { "platform": "twitch", "channel_name": "shroud", "stream_id": "41976921163", "stream_start": "2023-03-18 19:05:30", "stream_end": "2023-03-19 03:35:00", "total_subs": 78, "min_income_from_subs_in_$": 147, "max_income_from_subs_in_$": 210, "new_subs": 34, "re_subs": 39, "paid_subs": 73, "gifted_subs": 5, "prime_subs": 48, "tier_1_subs": 29, "tier_2_subs": 0, "tier_3_subs": 1 } }

Chat analytics

Chat volume and engagement for one broadcast — the aggregated numbers, not the messages themselves. For the messages, see chat logs. Available for Twitch, Kick, and YouTube.

GET /api/v2/channels/{name}/streams-extra/{stream-id}/chat?platform={platform}
Set of metricsAvailabilityCost / request
Chat analyticstwitch, kick, youtube1
RESPONSE · TwitchJSON
{ "data": { "platform": "twitch", "channel_name": "shroud", "stream_id": "41976921163", "total_messages": 9728, "total_words_count": 64447, "active_chatters": 3579, "passive_chatters": 143478, "messages_per_chatter": 2.7, "chat_engagement_rate_%": 2.4337501785, "chatters_with_1_message": 2198, "chatters_with_2+_message": 1381, "cheer_messages": 1, "cheer_chatters": 1, "total_bits": 1000, "income_from_bits_in_$": 10, "bits_per_cheered_message": 1000, "bits_per_cheered_chatter": 1000 } }
RESPONSE · Kick / YouTubeJSON
{ "data": { "platform": "youtube", "channel_name": "UCWsDFcIhY2DBi3GB5uykGXA", "channel_display_name": "IShowSpeed", "stream_id": "10203361939495629149", "total_messages": 101879, "total_words_count": 324669, "active_chatters": 17866, "messages_per_chatter": 5.7, "chatters_with_1_message": 8282, "chatters_with_2+_message": 9584, "active_chatters_to_viewers_ratio_%": 1.1 } }

Twitch chat data covers 200,000+ channels since January 2022. Kick covers 70,000+ since July 2025; YouTube covers top Gaming channels since July 2025. Slice a broadcast with time=YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM.

Two fields change type under a `time` window

With an exact-time window, passive_chatters and chat_engagement_rate_% come back as the string not available for timestamps instead of a number: both are defined over a full broadcast only. Every other counter — messages, chatters, bits — is recalculated for the window and sums back to the whole-stream figure. Parse those two fields as string-or-number, or read them from a request without time.

Chat logs NEW

The raw chat of one broadcast, message by message — timestamp, chatter, and text — instead of the aggregated counts returned by chat analytics. Use it for sentiment work, moderation review, emote and keyword analysis, or brand-mention tracking. Available for Twitch, Kick, and YouTube.

GET /api/v2/channels/{name}/streams-extra/{stream-id}/chat-logs?platform={platform}
Set of metricsAvailabilityCost
Chat log of one broadcasttwitch, kick, youtube1
One chat log, one credit

A chat log is priced per broadcast, not per message: 1 credit for the log of one stream, however many messages it holds. Long broadcasts are paginated, and following links.next through the same log is not charged again — x-credits-charged reports 1 on the first page and 0 on the rest. Requesting the same log after a new page cursor has expired starts a new charge.

REQUESTCURL
curl -X GET https://streamscharts.com/api/v2/channels/shroud/streams-extra/41976921163/chat-logs?platform=twitch \ -H 'Client-ID: XXXXXXXXXXXX' -H 'Token: YYYYYYYYYYYYYY'
RESPONSEJSON
{ "data": [ { "sent_at": "2023-03-18T19:05:41Z", "chatter_name": "someviewer", "message": "lets go sorc build", "bits": 0 }, { "sent_at": "2023-03-18T19:05:44Z", "chatter_name": "anotherviewer", "message": "PogChamp", "bits": 100 } ], "links": { "next": ".../chat-logs?platform=twitch&cursor=eyJvZmZzZXQiOjUwMDB9" }, "meta": { "stream_id": "41976921163", "stream_start": "2023-03-18 19:05:30", "stream_end": "2023-03-19 03:35:00", "total_messages": 9728, "per_page": 5000, "returned": 5000 } }

Response fields

FieldTypeDescription
sent_atstringISO 8601 UTC timestamp of the message.
chatter_namestringPlatform username of the chatter.
messagestringMessage text as sent, including emote codes.
bitsintegerBits cheered with the message. Twitch only; 0 when the message carried no cheer.
meta.total_messagesintegerMessages in the whole log — matches total_messages from chat analytics.
meta.per_pageintegerMessages per page. 5,000.

Paging and slicing

Messages come back in chronological order. Follow links.next until it is null rather than incrementing a page number — the cursor keeps you inside one log and keeps the follow-up pages uncharged. To read only part of a broadcast, pass an exact-time window: time=YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM.

Coverage

Twitch chat is stored for 200,000+ channels since January 2022; Kick for 70,000+ channels since July 2025; YouTube for top Gaming channels since July 2025. For YouTube, pass the channel ID in the path. Logs contain what was captured live — messages deleted by moderators after capture may still be present, and messages sent while collection was interrupted are absent.

User-generated content

Chat logs are personal data about identifiable users and may contain offensive text. Store and process them in line with the laws that apply to you, honour deletion requests, and do not use them to profile or target individual viewers.