TikTok Comments Scraper - Comments, Authors & Likes avatar

TikTok Comments Scraper - Comments, Authors & Likes

Pricing

from $1.00 / 1,000 results

Go to Apify Store
TikTok Comments Scraper - Comments, Authors & Likes

TikTok Comments Scraper - Comments, Authors & Likes

Scrape comments from TikTok videos using one or more video URLs or IDs. Extract comment text, author, likes, reply count and timestamp in clean structured data. Supports multiple videos in a single run with no login required.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

25

Total users

6

Monthly active users

15 days ago

Last modified

Categories

Share

TikTok Comments Scraper: Video Comments, Replies & Recurring Monitoring

TikTok Comments Scraper turns a video, or a creator's recent videos, into a clean comments dataset. Paste video links or ids, or give usernames and let the actor walk each account's recent videos, then filter by likes, a keyword, replies or age before anything is written. Every run can resume a large crawl, track changes across a schedule, and optionally pipe results into your own apps.

Why This Scraper?

  • Two ways to pick videos. Paste video links or ids, or give usernames and let the actor discover each account's recent videos.
  • Filters that save money. A minimum like count, a required keyword, a reply exclusion or a days-old cutoff are all applied before a row is written, so filtered-out comments are never billed.
  • Reply capture, honestly reported. Reply fetching is attempted per comment and switches itself off for a video once it is clear nothing is coming back, so you are never billed for a long stream of empty attempts.
  • Recurring monitoring. Incremental mode classifies every comment NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED against a remembered baseline, so a scheduled run returns only what changed.
  • Resume big crawls. Paste a previous run or dataset id and comments already collected there are skipped, so you never pay twice.
  • Export to your apps. Optionally pipe results into Notion, Linear, Airtable or Apify through connectors, without changing the dataset.
  • A quiet zero is never called a success. A run that collects nothing is reported clearly, so a scheduled job cannot fail silently.

Use Cases

  • Brand and campaign teams: track sentiment and engagement on your own or a competitor's TikTok videos.
  • Community managers: pull recent comments for moderation review, filtered to a keyword or a minimum like count.
  • Researchers and analysts: build a dataset of comment text, likes and timestamps across a set of videos or creators.
  • Growth and marketing teams: monitor a creator's newest videos on a schedule and get only new or changed comments.
  • Customer feedback teams: search a brand account's videos for comments that mention a product or keyword.

Data You Get

Sample shape: values are illustrative placeholders, not from a live video.

FieldExample
recordType, sourceMode"comment", "comments"
commentId"7685134583982015250"
videoId"7673909736131038495"
videoUrl"https://www.tiktok.com/video/7673909736131038495"
isReplyfalse
replyToCommentIdnull
text"This made my day"
authorUsername"sampleuser"
authorUid"7000000000000000002"
authorAvatarUrl"https://p16-sign-va.tiktokcdn.com/sample-avatar.jpeg"
authorNickname, authorRegion"Sample User", "US"
diggCount12
replyCommentTotal3
createTime, createTimeIso1700000000, "2023-11-14T22:13:20.000Z"
scrapedAt"2026-01-01T00:00:00.000Z"
cid, uid, uniqueId, avatarThumbnail, createTimeISOAliases of commentId, authorUid, authorUsername, authorAvatarUrl, createTimeIso (same values, for drop-in use with other TikTok comment exports)
repliesToIdParent comment id on a reply, null on top-level comments (alias of replyToCommentId)
videoWebUrl, submittedVideoUrl, inputThe video's web URL, the video URL it was collected for, and the URL / id / username you entered
likedByAuthor, pinnedByAuthortrue / false when the source says; null when it does not
mentions, detailedMentions@handles in the comment, and mentioned users with userId, userUniqueId, secUid and text offsets (empty arrays when none)
images, stickerImage URLs attached to the comment (empty array when none) and the sticker (id, staticUrl, animateUrl, width, height; null when none)
changeType, changedFields, firstSeenAt, lastSeenAtIncremental mode only: "NEW", ["diggCount"] (UPDATED rows), and ISO timestamps

Every comment is one record of this shape; there is no separate record type for videos or authors. A video's own metadata is not scraped, only the comment fields above, and authorUsername, diggCount and a few other fields can come back null when the source omits them for a particular comment.

How to Use

  1. Pick a mode: videos (paste the exact videos you care about) or search (give usernames and let the actor walk their recent videos). Search mode only follows a given account's own videos; it does not run a keyword or hashtag search across TikTok.
  2. Add your video URLs or ids, or your usernames. Paste the full video URL or the numeric video id (accepted shapes are in the table below); short share links (vm.tiktok.com, vt.tiktok.com) are not resolved and are skipped with a warning. A private or removed video returns no comments.
  3. Turn on any filters you want (minimum likes, a keyword, replies on or off, a days window), and set Max comments per video (and Max videos per username in search mode) to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Videos mode, the exact videos you care about:

{
"mode": "videos",
"videoUrls": ["https://www.tiktok.com/@tiktok/video/7673909736131038495"],
"maxCommentsPerVideo": 50
}

Search mode, walk an account's recent videos:

{
"mode": "search",
"usernames": ["tiktok"],
"maxVideosPerUser": 10,
"maxCommentsPerVideo": 50
}

Filtered comments, only what matters:

{
"mode": "videos",
"videoUrls": ["https://www.tiktok.com/@tiktok/video/7673909736131038495"],
"minCommentLikes": 10,
"commentKeyword": "love",
"excludeReplies": true,
"commentsSinceDays": 30
}

Recurring monitoring, only what changed since last time:

{
"mode": "videos",
"videoUrls": ["https://www.tiktok.com/@tiktok/video/7673909736131038495"],
"incrementalMode": true,
"stateKey": "my-campaign"
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/tiktok-comments-scraper").call(run_input={
"mode": "videos",
"videoUrls": ["https://www.tiktok.com/@tiktok/video/7673909736131038495"],
"maxCommentsPerVideo": 50,
})
for comment in client.dataset(run["defaultDatasetId"]).iterate_items():
print(comment["authorUsername"], comment["text"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/tiktok-comments-scraper').call({
mode: 'videos',
videoUrls: ['https://www.tiktok.com/@tiktok/video/7673909736131038495'],
maxCommentsPerVideo: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

About patience and caps

The source answers only a share of requests, and only during certain windows, some of which let almost nothing through. concurrency is how many requests the actor tries at once for a page, and pagePatienceSeconds is how long it keeps sampling before giving up on that page, so a window that opens partway through is still caught. maxAttemptsPerPage is an optional hard ceiling on top of that budget; leave it at 0 to let the patience budget alone decide. If a video keeps coming back as unreadable, raising pagePatienceSeconds (for example to 240) usually helps more than adding retries.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset id and the actor skips every comment id already collected there, so you don't pay twice. It cannot be combined with Incremental mode in the same run.
  • Incremental mode (incrementalMode) is for scheduled runs over the same videos or accounts. Each comment is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED or EXPIRED. A comment is only marked EXPIRED, and only when emitExpired is on, after a run that reached the natural end of every tracked video or account, with no block or resume, and with Max comments per video (and, in search mode, Max videos per username) set to 0 or high enough that the cap was never reached. In search mode, any video selection that leaves some of the account's listed videos out (Post sorting other than latest with a smaller Max videos per username, a post date window, or Exclude pinned posts) also counts as a partial walk and never marks anything EXPIRED. REAPPEARED only follows a comment that was previously tombstoned EXPIRED and is then seen again. stateKey names or shares the stored baseline; leave it empty to let the actor derive one from the videos, usernames, the number you entered in Max videos per username, the post selection options and the filters. UPDATED fires when ANY output field changes, not only the comment text, diggCount or replyCommentTotal: author flags such as likedByAuthor and pinnedByAuthor, authorNickname, mentions and images count too, and changedFields names what changed. Only scrapedAt, authorAvatarUrl (a signed, rotating picture link), avatarThumbnail, submittedVideoUrl, input and the fields you list in ignoreFieldsForChanges are left out; they stay in the output. A capped or partial walk never marks anything EXPIRED. With Incremental mode off, output is exactly as before.

Send results into your apps (MCP connectors)

Optionally pipe the scraped comments into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each comment, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringvideosvideos = scrape the URLs/ids you paste; search = walk usernames' videos.
videoUrlsarraythe 2 sample video URLs below (two different videos)Video URLs or numeric video ids. Videos mode. Short share links are not supported. Changed from []: a run started with no input now scrapes the sample videos instead of nothing.
usernamesarray[] (prefill: tiktok)TikTok usernames, with or without @. Search mode.
maxVideosPerUserinteger10How many of each account's recent videos to scan. 0 = the maximum (10,000). Search mode.
profileSortingstringlatestSearch mode: latest, popular (most liked) or oldest. popular and oldest rank the account's 500 most recent videos.
profileScrapeSectionsarray["videos"]Search mode: only videos is available. reposts is not exposed by the source, so a reposts-only request scans nothing and logs a warning.
oldestPostDateUnifiedstring(none)Search mode: skip videos older than this (YYYY-MM-DD, or an age like 30 / 2 weeks).
newestPostDatestring(none)Search mode: skip videos newer than this date.
excludePinnedPostsbooleanfalseSearch mode: leave out videos pinned to the top of the profile.
topLevelCommentsPerPostinteger0Stop after this many top-level comments per video that pass your filters (replies and filtered-out comments do not count). 0 = no separate limit.
minCommentLikesinteger0Only keep comments with at least this many likes. 0 = no minimum.
commentKeywordstring(none)Only keep comments containing this word or phrase, case-insensitive.
excludeRepliesbooleanfalseDrop replies and keep only top-level comments.
commentsSinceDaysinteger0Drop comments older than this many days. 0 = no date filter.
fetchRepliesbooleanfalseAlso try to collect replies. The source usually returns none to automated requests.
maxRepliesPerCommentinteger5Reply cap per comment when reply fetching is on. 0 = the maximum (1,000).
replyPatienceSecondsinteger10Time budget per reply request.
maxCommentsPerVideointeger20Comments to collect per video. 0 = the maximum (100,000).
maxPagesPerVideointeger0Reserved; currently has no effect. Use Max comments per video to limit run size.
pagePatienceSecondsinteger120Per-page time budget; a page keeps being requested until it succeeds or this runs out.
maxAttemptsPerPageinteger0Optional hard ceiling on requests per page. 0 = no ceiling.
concurrencyinteger20Parallel requests per page, 1 to 20.
resumeFromRunIdstring(none)Previous run or dataset id; comments already collected there are skipped.
incrementalModebooleanfalseClassify each comment against the remembered baseline and suppress unchanged rows.
stateKeystring(none)Optional name for this monitoring campaign. Leave empty to derive one automatically.
ignoreFieldsForChangesarray[]Incremental mode only. Extra top-level field names to exclude from UPDATED change detection, on top of the built-in exclusions (scrapedAt, authorAvatarUrl, avatarThumbnail, submittedVideoUrl, input). Any other output field, including the author flags, can trigger UPDATED.
emitUnchangedbooleanfalseAlso return (and bill) comments that did not change.
emitExpiredbooleanfalseAlso return (and bill) comments that are gone, only after a complete tracked scan.
mcpConnectorsarray(none)Optional MCP connectors to also send results to. Never changes the dataset.
notionParentPageUrlstring(none)Notion parent page for the Notion connector only.
maxNotifyListingsinteger50Cap on items sent to each connector per run.
proxyTierstringdatacenterdatacenter or residential. Measured 2026-10-15 through Apify Proxy, datacenter and residential both pass only a few percent of requests (1/40 vs 0/40), so datacenter stays the default; residential is a fallback, not an improvement.
proxyobject(none, prefill: {"useApifyProxy": true})Leave unset to use Apify Proxy automatically; proxyTier above picks the group.

Accepted URL shapes

ShapeExampleResult
Canonical videohttps://www.tiktok.com/@tiktok/video/7673909736131038495scraped
Canonical with query stringhttps://www.tiktok.com/@tiktok/video/7673909736131038495?lang=enscraped
Mobile/legacyhttps://m.tiktok.com/v/7673909736131038495.htmlscraped
Bare numeric id7673909736131038495scraped
Profile URL / @name / name in usernames (search mode)https://www.tiktok.com/@tiktokvideos walked
Profile URL in videoUrlshttps://www.tiktok.com/@tiktokskipped with a warning
Short share linkhttps://vm.tiktok.com/ZMabc123/skipped with a warning

An empty videoUrls in videos mode scrapes the two sample videos, not nothing (the default lists two different sample videos).

Output Example

Sample shape: values are illustrative placeholders, not from a live video.

{
"recordType": "comment",
"sourceMode": "comments",
"commentId": "7685134583982015250",
"videoId": "7673909736131038495",
"videoUrl": "https://www.tiktok.com/video/7673909736131038495",
"isReply": false,
"replyToCommentId": null,
"text": "This made my day",
"authorUsername": "sampleuser",
"authorNickname": "Sample User",
"authorUid": "7000000000000000002",
"authorAvatarUrl": "https://p16-sign-va.tiktokcdn.com/sample-avatar.jpeg",
"authorRegion": "US",
"diggCount": 12,
"replyCommentTotal": 3,
"createTime": 1700000000,
"createTimeIso": "2023-11-14T22:13:20.000Z",
"scrapedAt": "2026-01-01T00:00:00.000Z"
}

Output tabs and run summary

The Output tab offers three table views of the same comment rows: Comments (everything), Replies (every comment row, shown with reply-focused columns; replies are the rows where isReply is true, top-level comments appear too with an empty replyToCommentId) and Changes (incremental monitoring columns such as changeType and changedFields; filled when incrementalMode is on). A run with two or more distinct videos (by video id; the same video pasted in several shapes counts once) or two or more distinct usernames also saves a run summary under the key OUTPUT in the run's key-value store (comments pushed, unreachable videos, videos with no comments, filtered out).

Plan Requirement

This actor is pay-per-event, with three events as registered on the Pricing tab (which shows the current rates):

  • Actor Start (apify-actor-start): one event per GB of run memory (minimum one), charged once when the run starts.
  • Result (apify-default-dataset-item): one event per comment written to the dataset.
  • Reply fetch attempted (reply-fetch): one event per comment the actor tries to fetch replies for, only when Fetch replies is on, whether or not any reply rows come back. Replies are fetched, and charged, only for top-level comments that passed your filters (minimum likes, keyword, days window); comments dropped by a filter are never charged. Reply rows that do come back are billed as Results.

Proxy requirement. The default tier is datacenter. Measured 2026-10-15 through Apify Proxy, datacenter and residential both pass only a few percent of requests (1/40 vs 0/40), so datacenter stays the default; residential is a fallback, not an improvement. The comment API answers only a small share of requests per attempt on either tier. If a run returns too few comments, switch Proxy tier to residential under Proxy & connection and raise pagePatienceSeconds. Apify free plans do not include Apify Proxy or residential proxies. When the selected connection is refused, the actor prints:

The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs.

and, once a page is served that way: "Served over the backup connection (the default connection was unavailable)." If no page can be loaded at all, the run fails with one of these messages:

  • Proxy refused for the account: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
  • Residential unavailable and backup also failed: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested TikTok pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
  • Any other connection failure: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

FAQ

How much does it cost?

This actor uses pay-per-event pricing: a charge when the run starts, a charge for each comment written to the dataset, and a small charge each time the actor attempts to fetch replies for a comment (only when Fetch replies is on), whether or not any reply rows come back. The Pricing tab shows the current rates. Use Max comments per video to cap the size, and cost, of any run.

This actor collects only comments that are publicly visible on TikTok. You are responsible for how you use the data: follow TikTok's terms and the laws that apply to you, and get legal advice before any commercial use, especially one that stores or republishes personal data such as usernames or comment text.

Can I get only new or changed comments on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then classifies every comment against what was remembered from earlier runs on the same State key: NEW, UPDATED (with the changed fields listed), or UNCHANGED (suppressed and not billed unless Emit unchanged is on). A comment is only reported EXPIRED after a run that reached the natural end of every tracked video or account, with no block or resume, and with Max comments per video (and, in search mode, Max videos per username) set to 0 or high enough that the cap was never reached, with no post date window, Exclude pinned posts or ranked Post sorting trimming the account's video list, and only when Emit expired is on. A comment is only reported REAPPEARED once it was previously tombstoned EXPIRED and is then seen again. Because the source can return a slightly different comment list from one request to the next, a schedule may legitimately report a few new rows every run.

Why does turning on Fetch replies usually add nothing?

The source rarely returns reply rows to automated requests, even with Fetch replies on. The actor still tries, since some accounts and windows do return them, but gives up on a video after three attempts in a row come back empty. Every attempt is billed once, whether or not it returns a row, because the request itself has a real cost; any reply rows that do come back are billed separately as ordinary results.

Why did my run fail instead of returning an empty dataset?

A run that collects zero comments is reported as failed, not as a quiet empty success, whenever at least one video could not be read or returned no comments at all from the source. If every video was read and returned comments, but none were written because your filters removed them, a resumed run had already collected them, or incremental mode found nothing changed, the run finishes successfully with a message saying the result is genuinely empty.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

πŸ”— Want more TikTok data?

Pair this actor with these related scrapers from the same team:

πŸ“± TikTok Profile, Hashtag, Search, Video & Trending Scraper
Scrape TikTok without login. Extract profiles, bios, follower stats and videos; search by...
πŸ“± Tiktok Live Recorder
Record TikTok live streams to MP4 with full metadata, all stream quality URLs, and...
🧩 TikTok Shop Scraper
Scrape TikTok Shop by keyword, category or product URL. Extract prices, discounts, sales...
🧩 Dzen.ru Scraper
Scrape Dzen.ru (ex Yandex.Zen): articles, videos and channels. Full article text with...
πŸ“± Lemon8 Feed Scraper
Scrape Lemon8 feeds across 22 categories and 10+ regions. Extract posts, images, videos...
🧩 Pikabu Scraper
Scrape Pikabu (ΠŸΠΈΠΊΠ°Π±Ρƒ): keyword search, hot/new/best feeds, communities, tags, full story...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • πŸ› οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.