Twitch Scraper — Channels, Streams, Clips & VODs avatar

Twitch Scraper — Channels, Streams, Clips & VODs

Pricing

from $2.10 / 1,000 results

Go to Apify Store
Twitch Scraper — Channels, Streams, Clips & VODs

Twitch Scraper — Channels, Streams, Clips & VODs

Scrapes public Twitch data with no login or API key: channel profiles and follower counts, live stream status and viewers, top categories, clips, past broadcasts and search. Anonymous access is capped at 30 rows per query by Twitch, and every run reports it.

Pricing

from $2.10 / 1,000 results

Rating

0.0

(0)

Developer

Ibnu Adzim

Ibnu Adzim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Public Twitch data, with no login, no API key and no OAuth app to register.

⚠️ Requires a residential proxy

Twitch gates this API by exit-IP reputation. From a residential connection every request succeeds. From a datacenter IP — which is what Apify runs on by default — Twitch answers failed integrity check on even a single simple lookup, and a freshly minted Client-Integrity token does not lift it (verified on real cloud runs, bare and through two datacenter proxy groups).

Set proxyConfiguration to Apify Proxy with the RESIDENTIAL group before running. Without it every row comes back as an integrity_refused error naming this exact cause — the actor fails loudly rather than returning empty data.

Six things in one actor, chosen with a mode setting:

ModeYou give itYou get back
Channel profileschannel names or URLsprofile, follower count, live status, social links
Live streamsa category name (or nothing)who's live now, viewers, title, tags, category
Top categoriesthe most-watched categories right now, with viewer counts
Clipschannel namestop clips, views, duration, who clipped them
Videos (VODs)channel namespast broadcasts, highlights, uploads
Searchsearch termsmatching channels and categories

Why use this actor

  • No credentials at all. Twitch's official API needs a registered developer app and an OAuth token. This needs neither — nothing to set up, nothing to expire.
  • Live status in one field. isLive is a real boolean, plus viewer count, title, category and tags when the channel is streaming.
  • Exact numbers. Follower counts and viewer counts come back as integers (11287668), not "11.2M".
  • Working image URLs. Twitch serves preview images as templates containing {width}x{height}; those are filled in, so the URLs actually load.
  • Honest about limits. Every run writes a summary row stating the 30-row ceiling and why a result is the size it is.

The one limit you need to know

Twitch caps anonymous access at 30 rows per query, and refuses pagination.

Every cursor is rejected with failed integrity check. That was tested hard before this actor was designed around it — cursors inlined and as typed variables, from the first/middle/last edge, across five different connections, with a real integrity token, with device and session headers, and via Apollo persisted queries. It is structural, not a missing header.

So this actor does not promise deep crawls. Coverage comes from widening the query, and that genuinely works:

  • More channels or categories in queries — each is its own 30.
  • Clips: pick several time periods. They barely overlap. Measured on one channel: last week (25 clips) + last month (30) = 54 unique clips.
  • Live streams: pick several languages. The same category in three languages is three separate result sets.

Anyone claiming unlimited anonymous Twitch pagination is either using the official OAuth API or hasn't hit the ceiling yet.

Input

{
"mode": "channel",
"queries": ["shroud", "https://www.twitch.tv/kaicenat"],
"maxItems": 30
}
FieldTypeDescription
modestringchannel, streams, games, clips, videos, search.
queriesarrayChannel names/URLs, category names, or search terms — depends on mode. Empty is valid for streams (global) and games.
maxItemsintegerRows per query, max 30 (Twitch's ceiling).
clipPeriodsarrayClips mode: LAST_DAY, LAST_WEEK, LAST_MONTH, ALL_TIME. Several = more unique clips.
clipSortstringVIEWS_DESC (dependable), TRENDING, CREATED_AT_DESC.
broadcastTypestringVideos mode: ARCHIVE, HIGHLIGHT, UPLOAD, PAST_PREMIERE.
videoSortstringTIME or VIEWS.
streamSortstringVIEWER_COUNT, RECENT, RELEVANCE.
languagesarrayLive streams mode: restrict to broadcast languages (EN, ES, …).
maxConcurrencyintegerRequests in flight. Default 4.
minRequestIntervalnumberSeconds between request starts. Default 0.3.

Output

Rows share one envelope, told apart by recordType: CHANNEL, STREAM, GAME, CLIP, VIDEO, QUERY_SUMMARY, ERROR.

CHANNEL

{
"_input": "shroud",
"recordType": "CHANNEL",
"queryMode": "channel",
"channelId": "37402112",
"channelLogin": "shroud",
"channelName": "shroud",
"url": "https://www.twitch.tv/shroud",
"description": "I'm back baby",
"followers": 11287668,
"isPartner": true,
"createdAt": "2012-11-03T15:50:32Z",
"primaryColorHex": "00ADFF",
"avatarUrl": "https://static-cdn.jtvnw.net/jtv_user_pictures/...",
"socialLinks": [{ "name": "discord", "title": "Discord", "url": "https://discord.gg/shroud" }],
"isLive": false,
"streamGameName": "WARDOGS",
"lastBroadcastTitle": "stream stops when my bank account hits 0$"
}

When the channel is live it also carries liveTitle, liveViewerCount, liveStartedAt, liveGameName, liveTags and livePreviewImageUrl.

STREAM

{
"recordType": "STREAM", "queryMode": "streams", "resultRank": 1,
"streamId": "316782123862",
"title": "LIVE: BLAST Premier Open Porto 2026 - MOUZ vs Falcons",
"viewerCount": 56973,
"startedAt": "2026-08-31T08:11:01Z",
"channelLogin": "blastpremier",
"channelFollowers": 1284410,
"gameName": "Counter-Strike",
"tags": ["Esports", "English", "CS2"],
"previewImageUrl": "https://static-cdn.jtvnw.net/previews-ttv/live_user_blastpremier-1920x1080.jpg"
}

CLIP

{
"recordType": "CLIP", "resultRank": 1, "clipPeriod": "LAST_WEEK",
"clipId": "1222162697",
"title": "XDDD",
"url": "https://www.twitch.tv/shroud/clip/TentativeTenuousNeanderthalPanicBasket-...",
"viewCount": 153,
"durationSeconds": 11,
"createdAt": "2026-08-25T21:25:52Z",
"curatorLogin": "bonus_00",
"gameName": "WARDOGS"
}
FieldTypeDescription
channelLogin / channelNamestringLogin (URL name) and display name.
followersintegerExact follower count.
isLivebooleanWhether the channel is streaming right now.
viewerCountintegerLive viewers.
tagsarrayStream tags.
gameNamestringCategory.
viewCount / durationSecondsintegerClip and VOD metrics.
previewImageUrl / thumbnailUrlstringReady-to-use image URLs.
notesarrayHonesty flags on the summary row.

ERROR

Every input produces at least one row, so a bad channel is visible in the data:

{
"_input": "zzz_no_such_user_xyz",
"recordType": "ERROR",
"_error": "not_found",
"_errorDetail": "Twitch returned no channel for 'zzz_no_such_user_xyz'. The name may be misspelled, renamed, banned or deleted — this is a normal 200 with a null body, not a fetch failure."
}

Known limits

  • 30 rows per query, no pagination. Explained above. Widen the query instead.
  • TRENDING clips are often empty, and CREATED_AT_DESC currently answers a server error upstream. VIEWS_DESC is the dependable sort; the run says so when a sort returns nothing.
  • Empty VOD lists are normal. Twitch auto-deletes past broadcasts after 7–60 days depending on channel status.
  • No chat, no subscriber lists, no email addresses, no follower lists. Those are either private or require an authenticated account.
  • Stream ordering is approximate. Twitch layers its own recommendation weighting over the sort you pick.