Twitch Chat Scraper
Pricing
$0.05 / 1,000 chat messages
Twitch Chat Scraper
Collect public chat from Twitch VOD replays, live channels, or recent channel VODs. Get message text, timing, sender details, badges, subscriber status, emotes, and source context in an Apify dataset. No Twitch login or API token is needed.
Pricing
$0.05 / 1,000 chat messages
Rating
0.0
(0)
Developer
Maxime Dupré
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
4 days ago
Last modified
Categories
Share
🎮 Twitch chat from VODs and live channels
For stream researchers, moderators, developers, and analysts, Twitch Chat collects public messages from VOD replays, live channels, or recent channel VODs. Each dataset row includes message text, timing, sender details, badges, subscriber status, emotes, and Twitch source details, so you can review or analyze the chat in your own tools.
Use it to:
- Export messages from a public VOD with Twitch VOD Chat.
- Build a recent broadcast archive with Twitch Chat History.
- Collect visible messages from a live channel with Twitch Live Chat.
- Save a timestamped replay for review with Twitch Chat Replay.
- Download chat rows for later analysis with Twitch Chat Download.
- Collect chat rows that you can search in your dataset with Twitch Chat Search.
📦 Twitch chat rows
The Actor saves one row for each collected chat message. VOD replay and channel-history rows use these fields. Fields that Twitch does not provide can be missing.
| Field | Type | What it does |
|---|---|---|
text | string | The text in the chat message. |
messageId | string | The source ID of the message, when Twitch provides one. |
sentAt | string (date-time) | The time the message was sent, when Twitch provides it. |
streamOffsetSeconds | number | The message position in the VOD, in seconds, when Twitch provides it. |
collectionMode | string | The input mode: vod for a VOD replay or channelHistory for channel VOD history. |
source | object | The Twitch VOD that contains the message. |
source.type | string | The source kind. VOD replay and channel history rows use vod. |
source.id | string | The Twitch VOD ID, when available. |
source.url | string (URL) | The public Twitch page for the VOD, when available. |
source.title | string | The VOD title, when available. |
source.channel | string | The Twitch channel name, when available. |
source.channelId | string | The Twitch channel ID, when available. |
source.game | string | The game listed for the VOD, when available. |
sender | object | The Twitch user who sent the message. |
sender.userId | string | The sender's Twitch user ID, when available. |
sender.username | string | The sender's Twitch username, when available. |
sender.displayName | string | The name shown in Twitch chat, when available. |
sender.color | string | The sender's chat name color, when available. |
sender.isSubscriber | boolean | Whether the sender was a subscriber, when Twitch provides the status. |
sender.subscriptionTier | string | The sender's subscription tier, when available. |
sender.roles | array of strings | The Twitch chat roles shown for the sender, when available. |
sender.badges | array of objects | The Twitch chat badges shown for the sender, when available. |
sender.badges[].name | string | A badge name. |
sender.badges[].version | string | The badge version from Twitch, when available. |
emotes | array of objects | The emotes used in the message, with source IDs when available. |
emotes[].name | string | The emote name, when available. |
emotes[].id | string | The source emote ID, when available. |
emotes[].startIndex | integer | The start position of the emote in the message text, when available. |
emotes[].endIndex | integer | The end position of the emote in the message text, when available. |
Example VOD row:
{"text": "mraHappy mraHappy mraHappy","collectionMode": "vod","source": {"type": "vod","id": "2832981655","url": "https://www.twitch.tv/videos/2832981655","title": "Twitch Unity Guilds presents DRAGON GAMES : Legends of the Missing Temple w/ @stevesaylor and friends!","channel": "twitch","channelId": "12826","game": "Dungeons & Dragons"},"messageId": "4b74d16e-e8fe-4bf1-a8ce-a5a7d761b787","sentAt": "2026-07-30T19:52:40.179Z","streamOffsetSeconds": 100,"sender": {"userId": "811215975","username": "anonymousxjuan","displayName": "AnonymousxJuan","color": "#FF0000","isSubscriber": false,"badges": [{"name": "went-outside","version": "1"}]},"emotes": [{"name": "mraHappy","id": "emotesv2_0aca6a8a7e1c429ab0675022920e22a4","startIndex": 0,"endIndex": 7},{"name": "mraHappy","id": "emotesv2_0aca6a8a7e1c429ab0675022920e22a4","startIndex": 9,"endIndex": 16},{"name": "mraHappy","id": "emotesv2_0aca6a8a7e1c429ab0675022920e22a4","startIndex": 18,"endIndex": 25}]}
💬 Live Twitch messages
Live rows use the same message, source, and sender fields. They can also include live event and reply details. A live source may not provide a stream offset or emote list.
| Field | Type | What it does |
|---|---|---|
text | string | The text in the chat message. |
messageId | string | The source ID of the message, when Twitch provides one. |
sentAt | string (date-time) | The time the message was sent, when Twitch provides it. |
streamOffsetSeconds | number | The message position in the stream, when Twitch provides it. |
collectionMode | string | The input mode: live for an active public channel. |
source | object | The live Twitch channel that contains the message. |
source.type | string | The source kind: live. |
source.id | string | The Twitch channel ID, when available. |
source.url | string (URL) | The public Twitch page for the channel, when available. |
source.title | string | The live stream title, when available. |
source.channel | string | The Twitch channel name, when available. |
source.channelId | string | The Twitch channel ID, when available. |
source.game | string | The game listed for the live stream, when available. |
sender | object | The Twitch user who sent the message. |
sender.userId | string | The sender's Twitch user ID, when available. |
sender.username | string | The sender's Twitch username, when available. |
sender.displayName | string | The name shown in Twitch chat, when available. |
sender.color | string | The sender's chat name color, when available. |
sender.isSubscriber | boolean | Whether the sender was a subscriber, when Twitch provides the status. |
sender.subscriptionTier | string | The sender's subscription tier, when available. |
sender.roles | array of strings | The Twitch chat roles shown for the sender, when available. |
sender.badges | array of objects | The Twitch chat badges shown for the sender, when available. |
sender.badges[].name | string | A badge name. |
sender.badges[].version | string | The badge version from Twitch, when available. |
emotes | array of objects | The emotes used in the message, when available. |
emotes[].name | string | The emote name, when available. |
emotes[].id | string | The source emote ID, when available. |
emotes[].startIndex | integer | The start position of the emote in the message text, when available. |
emotes[].endIndex | integer | The end position of the emote in the message text, when available. |
event | object | Extra live-chat event details, when available. |
event.messageType | string | The Twitch message type, when available. |
event.bits | integer | The number of Twitch Bits in the message, when available. |
reply | object | The parent message context for a live-chat reply, when available. |
reply.parentMessageId | string | The source ID of the message being replied to, when available. |
reply.parentUsername | string | The username of the parent message sender, when available. |
reply.parentText | string | The text of the parent message, when available. |
Example live row:
{"text": "@CARD_878 hesRight","collectionMode": "live","source": {"type": "live","id": "71092938","url": "https://www.twitch.tv/xqc","title": "🧑🌾LIVE🧑🌾HERE🧑🌾LOCK IN🧑🌾DRAMA🧑🌾NEWS🧑🌾VIDEOSV🧑🌾REACTS🧑🌾TRHNIGS🧑🌾GAMES🧑🌾VIDEOGAMES🧑🌾MAYBE EVEN THINGS AND SUCH","channel": "xqc","channelId": "71092938","game": "Dark and Darker"},"messageId": "8de6dce8-6681-4a91-8117-139aea7bc240","sentAt": "2026-08-02T03:40:47.617Z","sender": {"userId": "926294771","username": "mtmf1_709","displayName": "mtmf1_709","isSubscriber": false},"event": {"messageType": "PRIVMSG"},"reply": {"parentMessageId": "175512e3-0243-434b-8bb1-67ee31a98376","parentUsername": "card_878","parentText": "wade otag is gato backwards"}}
▶️ Run a Twitch chat collection
- Choose
vod,live, orchannelHistoryintarget. - Add VOD URLs, a live channel, or channel IDs and names for the target you chose. Other target-option sections are ignored.
- Start the run and open the
datasetlink in the output. Each saved row is one chat message.
⚙️ Input
| Field | Type | What it does |
|---|---|---|
target | string | Choose vod, live, or channelHistory. The other Target Options sections are ignored. It defaults to vod. |
vodUrls | array of objects | Add one or more public Twitch VOD URLs. The same options apply to each VOD in the run. Twitch must make the chat replay available. |
vodUrls[].url | string (URL) | One public Twitch VOD URL. |
vodStartOffsetSeconds | integer | Start each VOD this many seconds into the stream. Leave empty to start at the beginning. |
liveChannel | string | Enter one public Twitch channel name or URL that is live now. The Actor stops when the run ends. |
liveMaxMessages | integer | Stop after this many live chat messages. Leave empty to collect all available messages during the run, until the source is exhausted. |
channelIds | array of strings | Add one or more public Twitch channel IDs or names. The Actor finds recent archived broadcasts for each channel and collects their available chat. |
channelMaxVods | integer | Stop after this many recent archived broadcasts for each channel. Leave empty to use all recent broadcasts Twitch makes available until the source is exhausted. |
maxMessagesPerVod | integer | For VOD chat replay and channel VOD history, stop each VOD after this many messages. Leave empty to collect all available messages until the source is exhausted. This setting is ignored for live channel chat. |
Example input:
{"target": "vod","vodUrls": [{"url": "https://www.twitch.tv/videos/2832981655"}],"vodStartOffsetSeconds": 100,"maxMessagesPerVod": 5}
🧾 Output
| Field | Type | What it does |
|---|---|---|
dataset | string (URL) | Link to the collected chat messages in the default dataset. It opens the dataset overview in Apify Console. |
The dataset holds the VOD, channel-history, or live message rows described above.
💳 Pricing
This Actor uses pay-per-event pricing. The chat-message event is charged for each visible Twitch chat message that is successfully saved from a public VOD replay or active public channel. Your total depends on how many messages are saved.
| Event | Price | What it covers |
|---|---|---|
chat-message | $0.00005 | One visible Twitch chat message from a public VOD replay or active public channel is saved to the dataset. |
🔌 Integrations
Open the dataset in Apify Console or fetch its items through the Apify API. Use the JSON data in your own review, search, moderation, or analysis workflow.
❓ FAQ
Does this collect live Twitch chat?
Yes. Choose live and enter a public channel that is live now. The Actor collects visible messages during the run and does not monitor the channel after the run ends.
Can I get a full available VOD replay?
Yes. Leave maxMessagesPerVod empty to collect all available messages until the source is exhausted. Twitch must expose the VOD chat replay for the Actor to collect it.
What if Twitch does not show the VOD chat replay?
The Actor cannot collect chat that Twitch does not expose publicly. This includes private, login-gated, expired, disabled-replay, or subscriber-only chat when the source does not make it available.
Can I collect more than one VOD or channel history?
Yes. Add more than one VOD URL or channel ID or name. The same options apply to each VOD in the run, and channelMaxVods sets the recent broadcast limit for each channel.
Can I start partway through a VOD?
Yes. Set vodStartOffsetSeconds to the start point you want. Leave it empty to start at the beginning.
Is this official Twitch chat?
No. This is an Apify Actor for chat that Twitch exposes publicly. It does not need a Twitch login or API token.
Does it download Twitch video or clips?
No. It collects chat messages and related Twitch data. It does not download or transform Twitch video or clip media.
Why is a field missing from a row?
Some fields are available only when Twitch provides them for that message or source. Check optional fields before using them instead of filling them with guessed values.
How can I search or export the chat?
Open the default dataset in Apify Console or fetch its items through the Apify API. You can then search the messages and use Apify's dataset export tools.
📝 Changelog
0.0: Initial release
🆘 Support
For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡
🔗 Related Actors
- Twitch Scraper — Find channel, stream, game, clip, and VOD metadata before choosing chat sources.
- Twitch VOD Chat Scraper — Full Chat Replay Export — Export a full chat replay from one public Twitch VOD.
- Twitch Messages Scraper — Collect live chat messages from an active Twitch channel.
- Twitch Streams & Channels Scraper — Find public streams, channels, categories, and recent videos before a chat run.
- Twitch VOD Downloader — Get structured VOD data or a stored video when chat is not the goal.
Made with ❤️ by Maxime Dupré