Twitch Chat Scraper avatar

Twitch Chat Scraper

Pricing

$0.05 / 1,000 chat messages

Go to Apify Store
Twitch Chat Scraper

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é

Maxime Dupré

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

4 days ago

Last modified

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:

📦 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.

FieldTypeWhat it does
textstringThe text in the chat message.
messageIdstringThe source ID of the message, when Twitch provides one.
sentAtstring (date-time)The time the message was sent, when Twitch provides it.
streamOffsetSecondsnumberThe message position in the VOD, in seconds, when Twitch provides it.
collectionModestringThe input mode: vod for a VOD replay or channelHistory for channel VOD history.
sourceobjectThe Twitch VOD that contains the message.
source.typestringThe source kind. VOD replay and channel history rows use vod.
source.idstringThe Twitch VOD ID, when available.
source.urlstring (URL)The public Twitch page for the VOD, when available.
source.titlestringThe VOD title, when available.
source.channelstringThe Twitch channel name, when available.
source.channelIdstringThe Twitch channel ID, when available.
source.gamestringThe game listed for the VOD, when available.
senderobjectThe Twitch user who sent the message.
sender.userIdstringThe sender's Twitch user ID, when available.
sender.usernamestringThe sender's Twitch username, when available.
sender.displayNamestringThe name shown in Twitch chat, when available.
sender.colorstringThe sender's chat name color, when available.
sender.isSubscriberbooleanWhether the sender was a subscriber, when Twitch provides the status.
sender.subscriptionTierstringThe sender's subscription tier, when available.
sender.rolesarray of stringsThe Twitch chat roles shown for the sender, when available.
sender.badgesarray of objectsThe Twitch chat badges shown for the sender, when available.
sender.badges[].namestringA badge name.
sender.badges[].versionstringThe badge version from Twitch, when available.
emotesarray of objectsThe emotes used in the message, with source IDs when available.
emotes[].namestringThe emote name, when available.
emotes[].idstringThe source emote ID, when available.
emotes[].startIndexintegerThe start position of the emote in the message text, when available.
emotes[].endIndexintegerThe 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.

FieldTypeWhat it does
textstringThe text in the chat message.
messageIdstringThe source ID of the message, when Twitch provides one.
sentAtstring (date-time)The time the message was sent, when Twitch provides it.
streamOffsetSecondsnumberThe message position in the stream, when Twitch provides it.
collectionModestringThe input mode: live for an active public channel.
sourceobjectThe live Twitch channel that contains the message.
source.typestringThe source kind: live.
source.idstringThe Twitch channel ID, when available.
source.urlstring (URL)The public Twitch page for the channel, when available.
source.titlestringThe live stream title, when available.
source.channelstringThe Twitch channel name, when available.
source.channelIdstringThe Twitch channel ID, when available.
source.gamestringThe game listed for the live stream, when available.
senderobjectThe Twitch user who sent the message.
sender.userIdstringThe sender's Twitch user ID, when available.
sender.usernamestringThe sender's Twitch username, when available.
sender.displayNamestringThe name shown in Twitch chat, when available.
sender.colorstringThe sender's chat name color, when available.
sender.isSubscriberbooleanWhether the sender was a subscriber, when Twitch provides the status.
sender.subscriptionTierstringThe sender's subscription tier, when available.
sender.rolesarray of stringsThe Twitch chat roles shown for the sender, when available.
sender.badgesarray of objectsThe Twitch chat badges shown for the sender, when available.
sender.badges[].namestringA badge name.
sender.badges[].versionstringThe badge version from Twitch, when available.
emotesarray of objectsThe emotes used in the message, when available.
emotes[].namestringThe emote name, when available.
emotes[].idstringThe source emote ID, when available.
emotes[].startIndexintegerThe start position of the emote in the message text, when available.
emotes[].endIndexintegerThe end position of the emote in the message text, when available.
eventobjectExtra live-chat event details, when available.
event.messageTypestringThe Twitch message type, when available.
event.bitsintegerThe number of Twitch Bits in the message, when available.
replyobjectThe parent message context for a live-chat reply, when available.
reply.parentMessageIdstringThe source ID of the message being replied to, when available.
reply.parentUsernamestringThe username of the parent message sender, when available.
reply.parentTextstringThe 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

  1. Choose vod, live, or channelHistory in target.
  2. Add VOD URLs, a live channel, or channel IDs and names for the target you chose. Other target-option sections are ignored.
  3. Start the run and open the dataset link in the output. Each saved row is one chat message.

⚙️ Input

FieldTypeWhat it does
targetstringChoose vod, live, or channelHistory. The other Target Options sections are ignored. It defaults to vod.
vodUrlsarray of objectsAdd 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[].urlstring (URL)One public Twitch VOD URL.
vodStartOffsetSecondsintegerStart each VOD this many seconds into the stream. Leave empty to start at the beginning.
liveChannelstringEnter one public Twitch channel name or URL that is live now. The Actor stops when the run ends.
liveMaxMessagesintegerStop after this many live chat messages. Leave empty to collect all available messages during the run, until the source is exhausted.
channelIdsarray of stringsAdd one or more public Twitch channel IDs or names. The Actor finds recent archived broadcasts for each channel and collects their available chat.
channelMaxVodsintegerStop after this many recent archived broadcasts for each channel. Leave empty to use all recent broadcasts Twitch makes available until the source is exhausted.
maxMessagesPerVodintegerFor 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

FieldTypeWhat it does
datasetstring (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.

EventPriceWhat it covers
chat-message$0.00005One 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 🫡

Made with ❤️ by Maxime Dupré