Social media · Video
Twitch Chat Scraper — VOD Chat Archive
Export the full timestamped chat replay attached to any public Twitch VOD as one row per message — user color, badges, emote IDs and message offsets included. No login.
Free Apify credit covers a first run. No credit card to try.
What this Actor scrapes
Twitch retains a complete timestamped chat replay for every VOD as long as the VOD itself exists. This Actor walks the same VideoCommentsByOffsetOrCursor GraphQL endpoint that Twitch's own VOD player uses, paginates by content offset (the only mode that avoids Twitch's integrity-check challenge), and emits one clean row per chat message — ready for analytics, moderation-classifier training, or post-broadcast review.
The Twitch chat archive endpoint is not part of the public Helix API; walking it reliably requires matching browser-level request fingerprints and absorbing residential-proxy rotation when Twitch rate-limits a single IP past roughly 10k messages. We handle that layer for you.
What we handle for you
- 🛡️ Browser fingerprint rotation —
curl-cffiimpersonates real Chrome / Firefox / Safari TLS handshakes so the target sees a browser, not Python. - 🌐 Residential proxy rotation via Apify Proxy — fresh session and exit IP on every block.
- 🔁 Retries with exponential backoff on
408 / 429 / 5xx— up to 5 attempts per page,Retry-Afterhonoured. - 🧱 Rate-limit-aware pacing — when the target pushes back, we slow down instead of getting banned.
- 🧊 Clean, typed dataset rows — Pydantic-validated, ISO-8601 timestamps, stable IDs, JSON / CSV / Excel export straight from the Apify Console.
- 💰 Pay-Per-Event pricing — $0.005 to start a run, then $0.001 per chat message in your dataset.
- 🔄 Channel back-catalog mode — point at a channel login and pull the N most-recent archive VODs in one run.
- 🎯 Offset filtering — skip the first N seconds of a VOD to focus on a specific segment.
Use cases
- Community sentiment analysis — bulk-export chat from your last 20 streams and run NLP for hype-moment detection.
- Moderation-classifier training — gather positive / negative chat samples at scale for an in-house spam or toxicity model. The
message_fragmentsfield preserves emote IDs so your model can learn emote semantics. - Esports analytics — quantify hype peaks against game events by joining message density (
message_offset_seconds) to the VOD timeline. - Post-broadcast review — streamers and mods download the twitch chat archive for an after-action review, username search, or clipping chat context.
- Academic research — public-record dataset of streamer-viewer conversation for media-studies and parasocial-dynamics research.
- Mod-tool development — feed historical chat into StreamElements / Streamlabs / Nightbot rule-testers without waiting for a live stream.
- chatdownloader alternative — drop-in managed replacement for local CLI tools; runs in Apify's cloud, no local setup, no proxy management.
Input
Paste this into the Apify Console, or send it as the run input over the API. Proxy settings are on by default; you rarely need to touch them.
| Field | Type | Required | What it does |
|---|---|---|---|
vodIds | array | no | List of Twitch VOD IDs or full VOD URLs (e.g. https://www.twitch.tv/videos/2773625679). Either this or channelLogin must be set. |
channelLogin | string | no | Twitch channel login (the URL slug, e.g. shroud) or the full channel URL (e.g. https://twitch.tv/shroud). Used only when vodIds is empty. The Actor fetches the most recent ARCHIVE VODs for this channel. |
maxRecentVods | integer | no | When channel mode is used, how many most-recent ARCHIVE VODs to pull (1–50). |
maxMessagesPerVod | integer | no | Stop walking chat once this many messages have been emitted for a single VOD (1–200000). A 6-hour stream typically has 5k–30k messages. |
startOffsetSeconds | integer | no | Skip chat messages whose offset within the VOD is less than this value. Use 0 to start from the beginning. |
{
"vodIds": [
"2773625679"
],
"maxMessagesPerVod": 100,
"startOffsetSeconds": 0,
"proxyConfiguration": {
"useApifyProxy": false
}
} Output
One row per result, schema-validated before it is written. Export JSON, CSV, Excel or XML from the run, or read it over the API.
vod_idoffset_secondscommenter_loginmessageuser_colorbadgesemote_idscreated_at
{
"vod_id": "2773625679",
"vod_title": "never played forza but i definitely have a drivers license so it should be easy",
"channel_login": "shroud",
"message_id": "1292e052-0561-4db5-86c7-adfc4556d628",
"message_offset_seconds": 12,
"posted_at": "2026-05-16T18:42:35.297Z",
"commenter_id": "142680597",
"commenter_login": "tabrexs",
"commenter_display_name": "tabrexs",
"message_text": "PewPewPew",
"message_fragments": [
{
"type": "emote",
"text": "PewPewPew",
"emote_id": "emotesv2_587405136a8147148c77df74baaa1bf4"
}
],
"user_color": "#DAA520",
"badges": [],
"is_subscriber": false,
"scraped_at": "2026-05-16T19:00:00Z"
} Pricing
| Event | Price | When |
|---|---|---|
| Actor start | $0.20 | Once per run, covers warm-up and proxy session setup. |
| Chat message emitted | $0.0010 | Per result written to the dataset. |
You pay only for results that land. Cap any run with maxTotalChargeUsd. See pricing & billing for worked examples.
Limitations
- VOD chat only, not live chat. Live chat is a separate IRC-over-WSS protocol; this Actor reads the VOD replay endpoint only. Once a broadcast ends and Twitch processes the VOD, the replay becomes available.
- No moderator-action log. The public chat-replay endpoint does not expose bans, timeouts, or deleted-message metadata. Deleted messages may appear as
<message deleted>or may not appear at all, depending on when they were removed. - VOD expiry. Default Twitch accounts retain VODs for 60 days. Partners, Affiliates, and Turbo subscribers retain indefinitely. Expired VODs return zero messages.
- Subscriber-only chat. If a VOD has subscriber-only chat enabled, anonymous queries return nothing. We surface the cause in the run status message.
- Rate-limits on long VODs. Twitch returns roughly 50–60 messages per page and rate-limits a single IP aggressively past ~10k messages. Residential proxy is strongly recommended for VODs with more than 10k messages. On the FREE Apify plan only the BUYPROXIES94952 datacenter group is provisioned by default; upgrade to residential for large VODs.
- GraphQL hash rotation. The persisted-query hash this Actor uses is a public Twitch web-player constant. If Twitch rotates it on a schema change, we ship a same-day patch. Subscribe to the Twitch Developers Discord
#announcementsfor early-warning.
FAQ
Does this scrape live chat?
Is this a chatdownloader alternative?
Why are some VODs returning zero messages?
How do I download Twitch chat to CSV?
Why does a long VOD take so long?
What about emote images?
emote_id in each emote fragment. Construct the CDN URL yourself: https://static-cdn.jtvnw.net/emoticons/v2/<emote_id>/default/dark/3.0.Is this a twitch chat dataset for NLP / toxicity training?
message_text + message_fragments fields, filter by is_subscriber if you need a specific audience slice, and join on message_offset_seconds to correlate with game events. We run a publicly available anonymised corpus on HuggingFace Datasets if you want a ready-made starting point.Ready to run it?
Open the listing on Apify, paste the input above, and watch rows land. If it ever breaks, it is our problem before it is yours.
Related Actors