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.
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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Standard | All platforms | 1 |
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, SteamTV | followers_gain |
| Rumble | followers_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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Extra | Twitch only | 1 |
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.
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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Standard + all stream games | All platforms | 1 |
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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Interval series | All platforms | 3 |
| Series + subscriber metrics | Twitch only | 4 |
| Series + chat metrics | twitch, kick, youtube | 5 |
| Series + chat + subscriber metrics | Twitch only | 6 |
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
| Parameter | Type | Description |
|---|---|---|
| platform | string | Required, as on every stream endpoint. |
| chat_metrics | boolean | true adds a chat block to every point. Adds 2 credits. |
| subs_metrics | boolean | true adds a subs block to every point. Adds 1 credit. |
| time | string | Exact-time window YYYY-MM-DD HH:MM,YYYY-MM-DD HH:MM — returns only the points inside it. Does not change the price. |
REQUESTCURLcurl -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
| Field | Type | Description |
|---|---|---|
| time | string | Start of the 5-minute bucket, UTC, YYYY-MM-DD HH:MM:SS — the same format as stream_start. |
| viewers | integer | Concurrent viewers at that moment. |
| auth_viewers | integer | null | Authorized viewers. Twitch only, and only for channels authorized on Streams Charts — null otherwise, and for the period before a channel authorized. |
| followers_gain | integer | null | Net 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_total | integer | null | Net follower change accumulated from the start of the broadcast to this point. |
| games | array | The 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_status | string | The title as the streamer set it at that moment — emoji, case and punctuation untouched. |
| chat.total_messages | integer | Messages in those 5 minutes. Only with chat_metrics=true. |
| chat.active_chatters | integer | Chatters who wrote at least once in those 5 minutes. |
| chat.bits_spent | integer | null | Bits cheered in those 5 minutes. Twitch only — null on Kick and YouTube. |
| subs.subs_gain | integer | New subscriptions in those 5 minutes. Only with subs_metrics=true. |
| subs.min_income_from_subs_in_$ | integer | Lower bound of estimated subscription income, accumulated from the start of the broadcast. |
| subs.max_income_from_subs_in_$ | integer | Upper 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
| Field | Type | Description |
|---|---|---|
| stream_start | string | Real start of the broadcast, to the second. |
| stream_end | string | Real 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_m | integer | Always 5. Read it instead of hard-coding the step. |
| points | integer | Number of points in data. |
| average_viewers | integer | Average concurrent viewers over the whole broadcast. |
| channel_average_viewers_30d | integer | The 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, Rumble | followers_gain, followers_gain_total |
| Every platform except Twitch | auth_viewers, the subs block, chat.bits_spent |
| Every platform except Twitch, Kick and YouTube | the chat block |
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.
| Rule | Behaviour |
|---|---|
| Window edges | Start inclusive, end exclusive — 09:00,09:30 returns 6 points, 09:00 through 09:25. |
| Edges off the 5-minute grid | Pulled 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 broadcast | Clipped to the broadcast; you get every point and nothing empty around it. |
| Window outside the broadcast | 404 not_found, not charged — probing for coverage costs nothing. |
| End before or equal to start | 422 invalid_parameter — time window end must be after start, not charged. |
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
nullpoints, no zero viewers. - The first point can be earlier than
stream_start.stream_startis second-precise; the first point is the bucket containing it, so a stream starting at08:36:45opens the series at08: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
timeon each point rather than assuming a fixed step. - No derived chat metrics per point.
passive_chattersandchat_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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Paid subscribers | Twitch only | 1 |
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.
| Set of metrics | Availability | Cost / request |
|---|---|---|
| Chat analytics | twitch, kick, youtube | 1 |
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.
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.
| Set of metrics | Availability | Cost |
|---|---|---|
| Chat log of one broadcast | twitch, kick, youtube | 1 |
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.
REQUESTCURLcurl -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
| Field | Type | Description |
|---|---|---|
| sent_at | string | ISO 8601 UTC timestamp of the message. |
| chatter_name | string | Platform username of the chatter. |
| message | string | Message text as sent, including emote codes. |
| bits | integer | Bits cheered with the message. Twitch only; 0 when the message carried no cheer. |
| meta.total_messages | integer | Messages in the whole log — matches total_messages from chat analytics. |
| meta.per_page | integer | Messages 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.
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.
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.