TikTok LIVE Comment Scraper
Pricing
$20.00 / 1,000 live capture minutes
TikTok LIVE Comment Scraper
Capture the live chat of a TikTok LIVE room while it is happening. One flat row per comment, with commenter identity where public, plus optional gift and join events. No login, no cookies, no WebSocket client to operate.
Pricing
$20.00 / 1,000 live capture minutes
Rating
0.0
(0)
Developer
Delowar Munna
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
24 days ago
Last modified
Categories
Share

Capture what the audience is actually saying, while it is being said.
Point this Actor at a TikTok LIVE room, say how long to listen, and get one clean row per comment — with commenter identity where public, plus optional gift and join events in the same dataset.
TL;DR
- Input: a live URL, an
@handle, a short link, or a room ID — plus how many minutes to listen. - Output: one flat, CSV-safe row per comment. Stable columns, ISO 8601 timestamps.
- Billing: per minute of capture, per room. Not per comment.
- No TikTok login, cookies, or API key required from you.
- There is no comment history. You get what arrives while the Actor is listening. See below.
⚠️ Read this first: live chat is ephemeral
TikTok exposes no endpoint that returns a live room's chat history. None. A comment that was posted before you started is not retrievable by this Actor or any other.
So "scrape the comments" here is not a lookup — it is a duration. You choose how long to listen, and how much you get depends on how busy the room is. A five-minute capture of a quiet room may return four comments; the same capture of a live-commerce drop may hit your cap in ninety seconds.
This single fact drives the input shape, the pricing unit, and the error model below.
Why choose this Actor
| Predictable cost | Billed per capture-minute, so you can compute your bill before pressing Start: rooms × captureMinutes. |
| Honest empty results | A quiet room and a room that is not live are normal outcomes. Both are reported clearly, and neither is charged. |
| Clean, flat schema | One row per comment, stable columns, no nested payloads to unpack. Exports to CSV without surprises. |
| Nothing to operate | No WebSocket client, no protobuf decoding, no signing service, no cookies. |
| Pipeline-ready | Output from TikTok LIVE Scraper pastes straight in — it is the discovery half of this pair. |
| Survives a room ending | If the broadcast ends mid-capture, everything already captured is kept and the early stop is flagged. |
Quick start in 3 steps
- Find a room that is live right now. Paste a live URL, or use TikTok LIVE Scraper to discover rooms worth listening to.
- Set
captureMinutes. Start with 5. This is what you pay for. - Run it. Rows appear in the dataset as they arrive — you do not have to wait for the run to finish to see results.
Minimal — one room, five minutes. Every other field has a sensible default.
{"liveRooms": ["https://www.tiktok.com/@examplecreator/live"],"captureMinutes": 5}
Several rooms at once. Rooms are captured concurrently, so three rooms for ten minutes takes
ten minutes of wall-clock, not thirty. Mix input styles freely — full URL, @handle, short link, or
a bare room ID all resolve the same way.
{"liveRooms": ["https://www.tiktok.com/@examplecreator/live","@anothercreator","https://vm.tiktok.com/ZMabcdefg/","7676761425155771157"],"captureMinutes": 10,"maxCommentsPerRoom": 2000,"maxTotalComments": 8000}
A longer listen with gifts and joins included. Use this shape for live-commerce sessions where you want the whole picture in one dataset.
{"liveRooms": ["@examplecreator"],"captureMinutes": 30,"includeGifts": true,"includeJoins": true,"includeCommenterFields": true,"deduplicateComments": true}
How capture works
- Resolve. Whatever you paste — live URL, short link,
@handle, or room ID — is normalised to a single room, and duplicates across notations collapse to one. - Check it is live. A room that is not live returns one
NOT_LIVErow and the run continues to the next room. It never fails the run, and it is never charged. - Listen. The Actor attaches to the room and records comments as they arrive, for
captureMinutes— or until the room ends, or until a cap is reached. - Write as it goes. Rows are pushed to the dataset continuously, so an interruption never costs you what was already captured.
- Summarise. A run summary is written to the key-value store under
SUMMARY.
Rooms are captured concurrently, up to five at a time. This matters: the rooms are live now, so capturing them one after another would mean the later rooms lose their first several minutes of chat permanently.
Input reference
| Field | Type | Default | Description |
|---|---|---|---|
liveRooms | array | [] | Live URLs, short links, @handles, bare handles, or room IDs. Required in practice. |
captureMinutes | integer | 5 | Minutes to listen per room. The cost driver. Max 60. |
maxCommentsPerRoom | integer | 1000 | Ceiling per room. Hitting it stops that room early — which also stops its billing. |
maxTotalComments | integer | 5000 | Absolute ceiling for the whole run. The hard cost cap. |
includeGifts | boolean | false | Also record gifts, as rows with eventType = gift. Free. |
includeJoins | boolean | false | Also record viewers joining, as eventType = join. High volume, low value — these count toward your caps. |
includeCommenterFields | boolean | true | Include the commenter identity block. |
deduplicateComments | boolean | false | Off by default — you get the raw stream. Turn on to drop repeat deliveries of the same message. See below. |
includeSummary | boolean | true | Write the run summary to the key-value store. |
proxyConfiguration | object | Apify Proxy | Datacenter or your own custom URLs. See the proxy policy below. |
About deduplicateComments
It matches on TikTok's per-message ID, never on comment text. Repetition in chat is signal, and none of it is affected:
- ten people posting "🔥" → ten separate rows
- one person posting "🔥" three times → three separate rows
What it removes is the same physical message reaching the Actor twice. That happens because the Actor replays the chat backlog when it connects, and again after any reconnect — typically 20–30% of messages in a short capture.
Default is off, so what you get is the raw stream exactly as it arrived. Two things to know if you leave it off:
- Repeat deliveries count toward
maxCommentsPerRoomandmaxTotalComments, so a cap can fill with messages you have already got. - Frequency analysis ("which question came up most?") will count protocol repeats as if they were real repeats. Turn deduplication on for that kind of work — especially for back-to-back scheduled runs, where windows overlap.
Billing is unaffected either way: you are charged per minute, not per row.
Worked cost examples
Because billing is per capture-minute, the arithmetic is simply rooms × captureMinutes:
| Run | Capture minutes billed |
|---|---|
| 1 room × 5 minutes | 5 |
| 3 rooms × 10 minutes | 30 |
| 5 rooms × 5 minutes, one of them not live | 20 — the offline room is free |
| 1 room × 30 minutes that ends after 12 | 12 — you pay for time actually captured |
| 1 room × 5 minutes with zero comments | 0 — a silent room is not charged |
1 room × 10 minutes that hits maxCommentsPerRoom at minute 3 | 3 |
You are billed only for capture minutes, and only for rooms that actually produced chat. There is no fee to start a run — a run that finds nothing live, or a room that stays silent, costs you nothing at all.
Live rates are on the Actor's Pricing tab. This README deliberately quotes no price amounts, so it cannot go stale.
Output reference
One row per captured event. Every row carries the same columns — including error rows — so CSV headers never shift mid-file.
Sample row — every column
Real output, captured 2026-08-22. One row per event, all 26 columns present on every row.
{"sourceRoomInput": "https://www.tiktok.com/@seniormender8/live","roomId": "7676761425155771157","roomUrl": "https://www.tiktok.com/@seniormender8/live","capturedAt": "2026-08-22T08:45:44.828Z","captureWindowSeconds": 60,"commentId": "7676774098299489056","commentText": "this new update is annoying🙄","commentTimestamp": "2026-08-22T08:44:22.727Z","commentLanguage": "en","eventType": "comment","position": 13,"creatorUsername": "seniormender8","liveTitle": "Zero Build Joker Fortnite!!","viewerCountAtCapture": 176,"roomStartTime": "2026-08-22T07:55:20.000Z","isRoomActive": true,"isPartial": false,"errorType": null,"errorMessage": null,"capturedSequence": 1,"commenterId": "7328783434984850464","commenterUsername": "sigrit_siki","commenterDisplayName": "✨️⚜ 𝑺.𝑳 ⚜✨️","commenterAvatarUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-no1a-avt-0068c001-no/712141b259ef9a695209407a36212c41~tplv-tiktok-shrink:72:72.webp?...","commenterVerified": false,"commenterFollowerCount": 23350}
(commenterAvatarUrl truncated here for readability — the real value is a full signed CDN URL.)
Dataset tabs
The dataset ships with four views. Pick one in the Console's Output tab, or append
?view=<name> to the dataset API URL — overview, commenters, gifts, issues.
📝 Comments — ?view=overview
The default. What was said, by whom, when.
{"eventType": "comment","commentText": "this new update is annoying🙄","commenterUsername": "sigrit_siki","commenterDisplayName": "✨️⚜ 𝑺.𝑳 ⚜✨️","commentTimestamp": "2026-08-22T08:44:22.727Z","commentLanguage": "en","creatorUsername": "seniormender8","roomId": "7676761425155771157","position": 13,"commentId": "7676774098299489056"}
👤 Commenters — ?view=commenters
The same rows projected onto who is talking — for audience analysis, follower-weighting, or spotting verified accounts in chat.
{"commenterUsername": "sigrit_siki","commenterDisplayName": "✨️⚜ 𝑺.𝑳 ⚜✨️","commenterId": "7328783434984850464","commenterVerified": false,"commenterFollowerCount": 23350,"commenterAvatarUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-no1a-avt-0068c001-no/...","commentText": "this new update is annoying🙄","roomId": "7676761425155771157"}
Note this is one row per comment, not one row per person — a viewer who comments five times
appears five times. Deduplicate on commenterId if you want unique people. The run summary already
does this for you as uniqueCommenters and topCommenters.
🎁 Gifts — ?view=gifts
Only populated when includeGifts is on. Gift rows sit in the same dataset as comments and are
distinguished by eventType.
{"eventType": "gift","giftSenderUsername": "someviewer","giftName": "Rose","giftCount": 5,"giftDiamondValue": 5,"commentTimestamp": "2026-08-22T08:44:31.180Z","creatorUsername": "seniormender8","roomId": "7676761425155771157"}
Shape shown from the schema, not from a capture. No gift arrived during testing, so unlike every other sample on this page this one is illustrative. The field mapping is verified against the protobuf definition; the values are not from a real run.
⚠️ Rooms with no result — ?view=issues
One row per room that produced nothing, saying why. This view is the reason an empty run is still a useful run — and none of these rows are charged.
{"sourceRoomInput": "@creatorwhoisoffline","errorType": "NOT_LIVE","errorMessage": "Room is not currently live","creatorUsername": "creatorwhoisoffline","roomId": null,"isRoomActive": false,"capturedAt": "2026-08-22T08:45:44.828Z"}
Shape shown from the schema. Every room in the sample run was live and talkative, so there were no rows to show here.
Columns
Source lineage — sourceRoomInput, roomId, roomUrl, capturedAt, captureWindowSeconds
Comment — commentId, commentText, commentTimestamp, commentLanguage, eventType, position
Commenter (when includeCommenterFields) — commenterId, commenterUsername,
commenterDisplayName, commenterAvatarUrl, commenterVerified, commenterFollowerCount
Room context — creatorUsername, liveTitle, viewerCountAtCapture, roomStartTime, isRoomActive
Gift (when includeGifts) — giftName, giftCount, giftDiamondValue, giftSenderUsername
Run metadata — isPartial, errorType, errorMessage, capturedSequence
eventType is comment, gift, join, or none (for a row explaining why a room produced
nothing). capturedSequence is the arrival order within its room; position is the order
across the whole run.
Run summary
Written to the key-value store under SUMMARY — never to the dataset, because a differently-shaped
row would corrupt CSV exports. It carries per-room counts, commentsPerMinute, uniqueCommenters,
topCommenters, what the pipeline filtered, and per-column fill rates.
commentsPerMinute is the metric worth watching: it tells you whether a room was worth listening to
and whether a longer capture would pay off.
What this Actor is NOT
- Not a chat-history tool. There is no history. This is the single most common misunderstanding.
- Not a video recorder. It captures chat, not the stream.
- Not a discovery tool. It listens to rooms you give it. Use TikTok LIVE Scraper to find rooms.
- Not a posting tool. It never comments, replies, follows, or sends anything.
- Not a private-data tool. Only what is publicly visible in the room.
- Not a sentiment classifier. It returns clean text for you to analyse, not opinions about it.
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
| Pointing it at a creator who is offline | One NOT_LIVE row, no charge | Check the creator is live first |
| Pasting a normal video URL | Treated as that creator's live room | Use the creator's live URL |
| Expecting past comments | You get only what arrives while listening | Increase captureMinutes, or schedule runs during the broadcast |
Setting captureMinutes very high on many rooms | Long run, larger bill | Bill = rooms × minutes; use maxTotalComments as a hard stop |
Turning on includeJoins in a busy room | Join rows crowd out comments against your caps | Leave it off unless you specifically want joins |
Troubleshooting
| Symptom | Meaning |
|---|---|
NOT_LIVE | The room was not broadcasting. Expected and free. |
NO_COMMENTS | The room was live but nobody commented in the window. Not charged. |
INVALID_INPUT | The entry could not be read as a live room. The row says why. |
UNRESOLVABLE | A short link or bare room ID could not be traced to a creator. |
SIGNATURE_RATE_LIMIT | Too many rooms connecting at once. Reduce the number of rooms per run. |
CONNECT_TIMEOUT | Could not attach in time; retried automatically before giving up. |
| Fewer rows than expected | The room was quiet, or a cap stopped capture early. Check SUMMARY. |
isPartial: true | The room ended mid-capture. What you have is complete up to that point. |
🚦 Proxy policy
Use Apify Datacenter proxy or no proxy for normal runs — both work reliably for TikTok LIVE rooms at this Actor's conservative concurrency.
Apify Residential proxy is not supported. The Actor fails at startup if apifyProxyGroups
includes RESIDENTIAL. Reason: in pay-per-event Actors, residential bandwidth (~$8/GB) is billed to
the developer, not the run user — and a capture holds an open connection for minutes, so a single
bandwidth-heavy run could exceed the revenue it generates.
If you genuinely need residential routing, supply your own provider via the proxy editor's Custom proxy URLs field. That traffic goes through your provider, not Apify, and is unaffected:
http://user:pass@proxy.iproyal.com:12321http://user:pass@proxy.brightdata.com:22225http://user:pass@proxy.oxylabs.io:7777
FAQ
Can I get comments from a stream that already ended? No. TikTok does not expose live chat history to anyone. If the broadcast is over, the chat is gone.
Do I need a TikTok account, cookies, or an API key? No.
What happens if the room ends while capturing?
Everything captured is kept, the row is flagged isPartial, and SUMMARY records
endedEarlyBecauseRoomClosed. You are billed only for the time actually captured.
Why is a quiet room not free... or is it? It is free. A room that produces zero comments is not charged at all, even though the Actor spent the full window listening.
Can I capture many rooms at once?
Yes — up to five concurrently per run. Beyond that, split across scheduled runs to avoid
SIGNATURE_RATE_LIMIT.
How do I capture a whole broadcast?
Set captureMinutes to cover it (max 60) and schedule back-to-back runs. Use deduplicateComments
so overlapping windows do not produce duplicate rows.
Integrations and scheduling
Works with everything on the Apify platform: Schedules (sample a room every hour through a broadcast), Webhooks, API, and integrations with Make, Zapier, Google Sheets, Slack and others. Because chat is ephemeral, scheduling is how you cover a long broadcast — a run every N minutes during the stream, with deduplication on.
Pair with TikTok LIVE Scraper: it finds rooms worth listening to and emits roomId/roomUrl
that paste into liveRooms unchanged.
Changelog
1.0 — Initial release. Live chat capture with gift and join events, commenter identity, room context, per-room and run-wide caps, deduplication, run summary, and per-capture-minute billing.