TikTok Comment & Reply Thread Extractor
Pull comments and reply threads from TikTok videos by URL or post ID, with pinned/hearted-by-author flags, commenter details, and like counts. No TikTok account or cookies required.
Input schema
Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.
| Field | Type | Required | Description |
|---|---|---|---|
postUrls | array | optional | TikTok video or photo URLs to scrape comments from (e.g. https://www.tiktok.com/@user/video/123...). |
postIds | array | optional | Numeric TikTok video IDs (15-20 digits) as an alternative to URLs. |
profiles | array | optional | TikTok usernames or profile URLs. The actor scrapes comments from their newest videos, up to 'Max videos per profile'. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
postUrls | array | optional | TikTok video or photo URLs to scrape comments from (e.g. https://www.tiktok.com/@user/video/123...). |
postIds | array | optional | Numeric TikTok video IDs (15-20 digits) as an alternative to URLs. |
profiles | array | optional | TikTok usernames or profile URLs. The actor scrapes comments from their newest videos, up to 'Max videos per profile'. |
maxVideosPerProfile | integer | optional | How many of each profile's newest videos to scrape comments from. |
maxCommentsPerPost | integer | optional | Maximum number of rows per video, counting replies when 'Include replies' is on. The actor walks the comment section as deep as TikTok serves it. |
includeReplies | boolean | optional | Fetch the reply thread under each root comment and emit each reply as its own row right after its parent. |
maxRepliesPerComment | integer | optional | Cap the replies fetched for any single root comment. Set to 0 for all replies (still bounded by 'Max comment rows per video'). |
maxItems | integer | optional | Global cap on the number of rows in the run (comments + replies). Set to 0 for no global cap. |
minLikes | integer | optional | Only keep comments and replies with at least this many likes. Comments below the threshold are skipped before their replies are fetched. |
includeVideoMetadata | boolean | optional | Add a 'video' object (caption, author, view/like/comment counts) to every row. |
includeCommenterDetails | boolean | optional | Add the commenter's region code and bio to user.region / user.bio, matched by comment ID from TikTok's app-style view of the page. |
includeCommenterStats | boolean | optional | Add exact follower, following, heart and video counts to user.* for every commenter. Each commenter's public profile is looked up once; private or banned accounts are omitted. |
maxCommenterLookups | integer | optional | Cap on how many commenters are enriched when 'Include commenter follower counts' is on. Set to 0 for no cap. |
deepWalk | boolean | optional | Read TikTok's app-style view of the comment list, which reaches far more comments on many videos, and restore image/sticker data from the standard view per comment. Off keeps the standard walk. |
Download the published input schema
View complete JSON
{
"description": "Scrape comments and full reply threads from TikTok videos. Provide video URLs/IDs and/or profiles.",
"properties": {
"deepWalk": {
"default": false,
"description": "Read TikTok's app-style view of the comment list, which reaches far more comments on many videos, and restore image/sticker data from the standard view per comment. Off keeps the standard walk.",
"prefill": false,
"title": "Deep walk (higher comment coverage)",
"type": "boolean"
},
"includeCommenterDetails": {
"default": false,
"description": "Add the commenter's region code and bio to user.region / user.bio, matched by comment ID from TikTok's app-style view of the page.",
"prefill": false,
"title": "Include commenter details (region, bio)",
"type": "boolean"
},
"includeCommenterStats": {
"default": false,
"description": "Add exact follower, following, heart and video counts to user.* for every commenter. Each commenter's public profile is looked up once; private or banned accounts are omitted.",
"prefill": false,
"title": "Include commenter follower counts",
"type": "boolean"
},
"includeReplies": {
"default": true,
"description": "Fetch the reply thread under each root comment and emit each reply as its own row right after its parent.",
"prefill": true,
"title": "Include replies",
"type": "boolean"
},
"includeVideoMetadata": {
"default": false,
"description": "Add a 'video' object (caption, author, view/like/comment counts) to every row.",
"prefill": false,
"title": "Include video metadata",
"type": "boolean"
},
"maxCommenterLookups": {
"default": 100,
"description": "Cap on how many commenters are enriched when 'Include commenter follower counts' is on. Set to 0 for no cap.",
"maximum": 10000,
"minimum": 0,
"prefill": 100,
"title": "Max commenter lookups",
"type": "integer"
},
"maxCommentsPerPost": {
"description": "Maximum number of rows per video, counting replies when 'Include replies' is on. The actor walks the comment section as deep as TikTok serves it.",
"maximum": 10000,
"minimum": 1,
"prefill": 5,
"title": "Max comment rows per video",
"type": "integer"
},
"maxItems": {
"default": 0,
"description": "Global cap on the number of rows in the run (comments + replies). Set to 0 for no global cap.",
"maximum": 1000000,
"minimum": 0,
"prefill": 0,
"title": "Max total rows",
"type": "integer"
},
"maxRepliesPerComment": {
"default": 0,
"description": "Cap the replies fetched for any single root comment. Set to 0 for all replies (still bounded by 'Max comment rows per video').",
"maximum": 5000,
"minimum": 0,
"prefill": 5,
"title": "Max replies per comment",
"type": "integer"
},
"maxVideosPerProfile": {
"default": 10,
"description": "How many of each profile's newest videos to scrape comments from.",
"maximum": 500,
"minimum": 1,
"prefill": 5,
"title": "Max videos per profile",
"type": "integer"
},
"minLikes": {
"default": 0,
"description": "Only keep comments and replies with at least this many likes. Comments below the threshold are skipped before their replies are fetched.",
"maximum": 1000000,
"minimum": 0,
"prefill": 0,
"title": "Minimum likes",
"type": "integer"
},
"postIds": {
"description": "Numeric TikTok video IDs (15-20 digits) as an alternative to URLs.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Video IDs",
"type": "array"
},
"postUrls": {
"description": "TikTok video or photo URLs to scrape comments from (e.g. https://www.tiktok.com/@user/video/123...).",
"editor": "stringList",
"items": {
"type": "string"
},
"prefill": [
"https://www.tiktok.com/@khaby.lame/video/7574844184952081686"
],
"title": "Video URLs",
"type": "array"
},
"profiles": {
"description": "TikTok usernames or profile URLs. The actor scrapes comments from their newest videos, up to 'Max videos per profile'.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Profiles (comments on their newest videos)",
"type": "array"
}
},
"required": [],
"schemaVersion": 1,
"title": "TikTok Comment & Reply Thread Extractor Input",
"type": "object"
}
Output schema
Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.
| Field | Type | Required | Description |
|---|---|---|---|
commentId | string | required | Unique numeric ID of the comment or reply. |
postId | string | required | Numeric ID of the TikTok video this comment belongs to. |
postUrl | string | required | URL of the TikTok video. |
rowType | string | optional | 'comment' for top-level comments, 'reply' for replies. |
text | string | optional | The text content of the comment or reply. |
createdAt | string | required | ISO 8601 timestamp when the comment was posted. |
likeCount | string | required | Number of likes on the comment. |
replyCount | string | required | Total number of direct replies to this comment. |
isPinnedByAuthor | string | required | True if the comment is pinned by the video author. |
isLikedByAuthor | string | required | True if the video author has liked this comment. |
isReply | string | required | True when this row is a reply to another comment rather than a top-level comment. |
replyToCommentId | string | optional | ID of the root comment this row replies to. Present only on reply rows. |
replyToReplyId | string | optional | For nested replies, the ID of the reply this row answers. |
replyToUsername | string | optional | Handle of the comment/reply being answered (reply rows). |
replyToNickname | string | optional | Display name of the comment/reply being answered (reply rows). |
replyToUserId | string | optional | Numeric user ID of the comment/reply being answered (reply rows). |
threadId | string | optional | ID grouping a root comment with its replies, when TikTok provides one. |
language | string | optional | Detected language code of the comment (e.g. 'en', 'es'). May be absent. |
isTranslatable | string | optional | Whether TikTok offers a translation for this comment. |
shareUrl | string | optional | TikTok share link that opens this comment. |
scrapedAt | string | optional | ISO 8601 timestamp when the row was collected. |
video | string | optional | Caption, author and stats of the source video (only when 'Include video metadata' is on). |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"description": "One record per TikTok comment or reply, with text, like/reply counts, pinned/hearted flags, reply-thread links, and commenter details.",
"properties": {
"commentId": {
"description": "Unique numeric ID of the comment or reply.",
"template": "{{commentId}}",
"title": "Comment ID",
"type": "string"
},
"createdAt": {
"description": "ISO 8601 timestamp when the comment was posted.",
"template": "{{createdAt}}",
"title": "Created At",
"type": "string"
},
"isLikedByAuthor": {
"description": "True if the video author has liked this comment.",
"template": "{{isLikedByAuthor}}",
"title": "Liked by Author",
"type": "string"
},
"isPinnedByAuthor": {
"description": "True if the comment is pinned by the video author.",
"template": "{{isPinnedByAuthor}}",
"title": "Pinned by Author",
"type": "string"
},
"isReply": {
"description": "True when this row is a reply to another comment rather than a top-level comment.",
"template": "{{isReply}}",
"title": "Is Reply",
"type": "string"
},
"isTranslatable": {
"description": "Whether TikTok offers a translation for this comment.",
"template": "{{isTranslatable}}",
"title": "Is Translatable",
"type": "string"
},
"language": {
"description": "Detected language code of the comment (e.g. 'en', 'es'). May be absent.",
"template": "{{language}}",
"title": "Language",
"type": "string"
},
"likeCount": {
"description": "Number of likes on the comment.",
"template": "{{likeCount}}",
"title": "Likes",
"type": "string"
},
"postId": {
"description": "Numeric ID of the TikTok video this comment belongs to.",
"template": "{{postId}}",
"title": "Post ID",
"type": "string"
},
"postUrl": {
"description": "URL of the TikTok video.",
"template": "{{postUrl}}",
"title": "Post URL",
"type": "string"
},
"replyCount": {
"description": "Total number of direct replies to this comment.",
"template": "{{replyCount}}",
"title": "Reply Count",
"type": "string"
},
"replyToCommentId": {
"description": "ID of the root comment this row replies to. Present only on reply rows.",
"template": "{{replyToCommentId}}",
"title": "Reply To Comment ID",
"type": "string"
},
"replyToNickname": {
"description": "Display name of the comment/reply being answered (reply rows).",
"template": "{{replyToNickname}}",
"title": "Reply To Nickname",
"type": "string"
},
"replyToReplyId": {
"description": "For nested replies, the ID of the reply this row answers.",
"template": "{{replyToReplyId}}",
"title": "Reply To Reply ID",
"type": "string"
},
"replyToUserId": {
"description": "Numeric user ID of the comment/reply being answered (reply rows).",
"template": "{{replyToUserId}}",
"title": "Reply To User ID",
"type": "string"
},
"replyToUsername": {
"description": "Handle of the comment/reply being answered (reply rows).",
"template": "{{replyToUsername}}",
"title": "Reply To Username",
"type": "string"
},
"rowType": {
"description": "'comment' for top-level comments, 'reply' for replies.",
"template": "{{rowType}}",
"title": "Row Type",
"type": "string"
},
"scrapedAt": {
"description": "ISO 8601 timestamp when the row was collected.",
"template": "{{scrapedAt}}",
"title": "Scraped At",
"type": "string"
},
"shareUrl": {
"description": "TikTok share link that opens this comment.",
"template": "{{shareUrl}}",
"title": "Share URL",
"type": "string"
},
"text": {
"description": "The text content of the comment or reply.",
"template": "{{text}}",
"title": "Comment Text",
"type": "string"
},
"threadId": {
"description": "ID grouping a root comment with its replies, when TikTok provides one.",
"template": "{{threadId}}",
"title": "Thread ID",
"type": "string"
},
"video": {
"description": "Caption, author and stats of the source video (only when 'Include video metadata' is on).",
"template": "{{video}}",
"title": "Video Metadata",
"type": "string"
}
},
"required": [
"commentId",
"postId",
"createdAt",
"likeCount",
"replyCount",
"isPinnedByAuthor",
"isLikedByAuthor",
"isReply",
"postUrl"
],
"title": "TikTok Comment & Reply Thread Extractor Output",
"type": "object"
}
Dataset schema
Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.
Download the published dataset schema
View complete JSON
{
"actorSpecification": 1,
"fields": {
"commentId": {
"description": "TikTok's unique comment ID (cid field)",
"title": "Comment ID",
"type": "string"
},
"createTime": {
"description": "Unix timestamp when the comment was posted",
"title": "Create Time (Unix)",
"type": "integer"
},
"createdAt": {
"description": "ISO 8601 UTC datetime when the comment was posted",
"title": "Created At",
"type": "string"
},
"images": {
"description": "Raw image_list from TikTok for comments with image attachments",
"title": "Images",
"type": "array"
},
"isLikedByAuthor": {
"description": "Whether the post author liked this comment (heart)",
"title": "Liked By Author",
"type": "boolean"
},
"isPinnedByAuthor": {
"description": "Whether the post author pinned this comment",
"title": "Pinned By Author",
"type": "boolean"
},
"isReply": {
"description": "True if this is a reply to another comment",
"title": "Is Reply",
"type": "boolean"
},
"isTranslatable": {
"description": "Whether TikTok offers a translation for this comment",
"title": "Is Translatable",
"type": "boolean"
},
"labels": {
"description": "Raw label_list entries TikTok attaches to the comment",
"title": "Labels",
"type": "array"
},
"language": {
"description": "Detected language code of the comment text",
"title": "Language",
"type": "string"
},
"likeCount": {
"description": "Number of likes/diggs on this comment",
"title": "Like Count",
"type": "integer"
},
"postId": {
"description": "TikTok post/video ID this comment belongs to",
"title": "Post ID",
"type": "string"
},
"postUrl": {
"description": "URL of the TikTok post",
"title": "Post URL",
"type": "string"
},
"replyCount": {
"description": "Total number of replies to this comment",
"title": "Reply Count",
"type": "integer"
},
"replyToCommentId": {
"description": "ID of the root comment this row replies to (reply rows)",
"title": "Reply To Comment ID",
"type": "string"
},
"replyToNickname": {
"description": "Display name of the comment/reply being answered",
"title": "Reply To Nickname",
"type": "string"
},
"replyToReplyId": {
"description": "For nested replies, the ID of the reply this row answers",
"title": "Reply To Reply ID",
"type": "string"
},
"replyToUserId": {
"description": "Numeric user ID of the comment/reply being answered",
"title": "Reply To User ID",
"type": "string"
},
"replyToUsername": {
"description": "Handle of the comment/reply being answered",
"title": "Reply To Username",
"type": "string"
},
"rowType": {
"description": "'comment' for top-level comments, 'reply' for replies",
"title": "Row Type",
"type": "string"
},
"scrapedAt": {
"description": "ISO 8601 timestamp when the row was collected",
"title": "Scraped At",
"type": "string"
},
"shareUrl": {
"description": "TikTok share link that opens this comment",
"title": "Share URL",
"type": "string"
},
"stickers": {
"description": "Raw cmt_sticker_struct when the comment uses a sticker",
"title": "Stickers",
"type": "object"
},
"text": {
"description": "Raw comment text content",
"title": "Comment Text",
"type": "string"
},
"textExtra": {
"description": "Raw textExtra entries from TikTok API — contains hashtags, mentions, and other inline annotations in the comment text",
"title": "Text Extra",
"type": "array"
},
"threadId": {
"description": "Thread identifier grouping root comment + all its replies",
"title": "Thread ID",
"type": "string"
},
"user": {
"description": "Author of the comment",
"properties": {
"avatarUrl": {
"title": "Avatar URL",
"type": "string"
},
"bio": {
"description": "Commenter profile bio when set (with 'Include commenter details')",
"title": "Bio",
"type": "string"
},
"displayName": {
"title": "Display Name",
"type": "string"
},
"followerCount": {
"description": "Commenter's exact follower count (with 'Include commenter follower counts')",
"title": "Follower Count",
"type": "integer"
},
"followingCount": {
"description": "Commenter's exact following count (with 'Include commenter follower counts')",
"title": "Following Count",
"type": "integer"
},
"heartCount": {
"description": "Total likes received by the commenter (with 'Include commenter follower counts')",
"title": "Heart Count",
"type": "integer"
},
"id": {
"title": "User ID",
"type": "string"
},
"region": {
"description": "Country/region code TikTok reports for the commenter (with 'Include commenter details')",
"title": "Region",
"type": "string"
},
"secUid": {
"title": "Secure UID",
"type": "string"
},
"username": {
"title": "Username",
"type": "string"
},
"verified": {
"title": "Verified",
"type": "boolean"
},
"videoCount": {
"description": "Number of public videos on the commenter's profile (with 'Include commenter follower counts')",
"title": "Video Count",
"type": "integer"
}
},
"title": "User",
"type": "object"
},
"video": {
"description": "Caption, author and stats of the source video (only when 'Include video metadata' is on)",
"properties": {
"authorNickname": {
"title": "Author Nickname",
"type": "string"
},
"authorUsername": {
"title": "Author Username",
"type": "string"
},
"collectCount": {
"title": "Collect Count",
"type": "integer"
},
"commentCount": {
"title": "Comment Count",
"type": "integer"
},
"createTime": {
"title": "Create Time (Unix)",
"type": "integer"
},
"createdAt": {
"title": "Created At",
"type": "string"
},
"desc": {
"title": "Caption",
"type": "string"
},
"id": {
"title": "Video ID",
"type": "string"
},
"likeCount": {
"title": "Like Count",
"type": "integer"
},
"playCount": {
"title": "Play Count",
"type": "integer"
},
"shareCount": {
"title": "Share Count",
"type": "integer"
}
},
"title": "Video Metadata",
"type": "object"
}
},
"title": "TikTok Comments & Replies",
"views": {
"overview": {
"description": "TikTok comments with engagement metrics and author info.",
"display": {
"component": "table",
"properties": {
"commentId": {
"format": "text",
"label": "Comment ID"
},
"createdAt": {
"format": "text",
"label": "Created At"
},
"isReply": {
"format": "text",
"label": "Is Reply"
},
"likeCount": {
"format": "number",
"label": "Likes"
},
"postId": {
"format": "text",
"label": "Post ID"
},
"replyCount": {
"format": "number",
"label": "Replies"
},
"replyToCommentId": {
"format": "text",
"label": "Reply To"
},
"rowType": {
"format": "text",
"label": "Type"
},
"text": {
"format": "text",
"label": "Comment Text"
},
"user": {
"format": "text",
"label": "User"
}
}
},
"title": "Comments Overview",
"transformation": {
"fields": [
"rowType",
"commentId",
"postId",
"text",
"createdAt",
"likeCount",
"replyCount",
"isReply",
"replyToCommentId",
"user"
]
}
},
"replies": {
"description": "Only reply rows, keyed by the root comment they answer.",
"display": {
"component": "table",
"properties": {
"commentId": {
"format": "text",
"label": "Reply ID"
},
"createdAt": {
"format": "text",
"label": "Created At"
},
"likeCount": {
"format": "number",
"label": "Likes"
},
"postId": {
"format": "text",
"label": "Post ID"
},
"postUrl": {
"format": "text",
"label": "Video"
},
"replyToCommentId": {
"format": "text",
"label": "Root Comment"
},
"replyToReplyId": {
"format": "text",
"label": "Answers Reply"
},
"replyToUsername": {
"format": "text",
"label": "Answers User"
},
"text": {
"format": "text",
"label": "Text"
},
"user": {
"format": "text",
"label": "User"
}
}
},
"title": "Replies",
"transformation": {
"fields": [
"commentId",
"postId",
"replyToCommentId",
"replyToReplyId",
"replyToUsername",
"text",
"createdAt",
"likeCount",
"user",
"postUrl"
]
}
},
"withVideo": {
"description": "Rows enriched with the source video's caption and stats.",
"display": {
"component": "table",
"properties": {
"commentId": {
"format": "text",
"label": "Comment ID"
},
"createdAt": {
"format": "text",
"label": "Created At"
},
"likeCount": {
"format": "number",
"label": "Likes"
},
"postUrl": {
"format": "text",
"label": "Video URL"
},
"rowType": {
"format": "text",
"label": "Type"
},
"text": {
"format": "text",
"label": "Comment Text"
},
"video": {
"format": "text",
"label": "Video"
}
}
},
"title": "With Video Metadata",
"transformation": {
"fields": [
"rowType",
"commentId",
"text",
"likeCount",
"createdAt",
"video",
"postUrl"
]
}
}
}
}
Key-value schema
Published key-value store definitions, when provided by this build.
This definition is not present in the default published build. See the published README for available documentation.
Published README
Read the full published documentation
TikTok Comment & Reply Thread Extractor
Pull the comment section of any public TikTok video — including the full reply thread under each comment — with no TikTok account, no cookies and no proxy setup. Every comment and reply becomes one dataset row, with its author, like count, timestamps and creator-engagement flags.
What this actor does
- Accepts TikTok video URLs, numeric video IDs, and/or profile names (scrapes the newest videos of each profile)
- Walks the comment section as deep as TikTok serves it, recovering far past the first few hundred comments on huge videos
- Fetches the reply thread under every root comment — replies are paged past TikTok's first reply batch, not truncated
- Emits each root comment followed immediately by its own replies, linked by
replyToCommentId(andreplyToReplyIdfor nested answers) - Flags pinned comments, creator-hearted comments, and translation availability
- Captures commenter handle, display name, numeric user ID, secUid and avatar, plus image and sticker comments
- Optionally attaches the source video's caption and stats (
includeVideoMetadata) - Optionally adds each commenter's region code and bio (
includeCommenterDetails) and exact follower/following/heart/video counts (includeCommenterStats) deepWalkmode recovers far more comments on videos where TikTok's default list stops early, restoring image/sticker data from the web payload per comment ID- Reports videos that are deleted, private or nonexistent as "unavailable" instead of silently empty
- Filters by minimum likes (
minLikes) and caps rows per video (maxCommentsPerPost) or per run (maxItems) - Omits empty fields everywhere — no nulls, no placeholders
Input
| Field | Type | Default | Description |
|---|---|---|---|
postUrls |
array | — | TikTok video/photo URLs to scrape comments from |
postIds |
array | — | Numeric video IDs (15–20 digits), alternative to URLs |
profiles |
array | — | Usernames or profile URLs — comments on their newest videos |
maxVideosPerProfile |
integer | 10 |
How many of each profile's newest videos to scrape |
maxCommentsPerPost |
integer | – (100 if not set) | Maximum rows per video (replies included) |
includeReplies |
boolean | true |
Fetch and emit reply threads |
maxRepliesPerComment |
integer | 0 |
Cap replies per root comment; 0 = all |
maxItems |
integer | 0 |
Global row cap for the run; 0 = no cap |
minLikes |
integer | 0 |
Keep only comments/replies with at least this many likes |
includeVideoMetadata |
boolean | false |
Attach a video object (caption, author, stats) to every row |
includeCommenterDetails |
boolean | false |
Add user.region and user.bio to every row |
includeCommenterStats |
boolean | false |
Add exact user.followerCount / followingCount / heartCount / videoCount |
maxCommenterLookups |
integer | 100 |
Cap on how many commenters are enriched by includeCommenterStats; 0 = no cap |
deepWalk |
boolean | false |
Read TikTok's app-style view of the comment list (much higher coverage on many videos) and restore image/sticker fields per comment; off keeps the standard walk |
Example: comments and replies for one video
{
"postUrls": ["https://www.tiktok.com/@khaby.lame/video/7574844184952081686"],
"maxCommentsPerPost": 500,
"includeReplies": true
}
Example: top comments only, no replies
{
"postUrls": ["https://www.tiktok.com/@natgeo/video/7640880319159094559"],
"maxCommentsPerPost": 200,
"includeReplies": false
}
Example: comments from a profile's newest videos
{
"profiles": ["mrbeast"],
"maxVideosPerProfile": 3,
"maxCommentsPerPost": 200,
"maxItems": 1000
}
Example: only highly-liked comments, with video metadata
{
"postIds": ["7574844184952081686", "7640880319159094559"],
"minLikes": 100,
"includeVideoMetadata": true
}
Output per comment or reply
rowType—commentfor top-level comments,replyfor repliescommentId— unique TikTok comment IDpostId— ID of the video the comment belongs topostUrl— URL of the videotext— comment text (absent on image/sticker-only comments)createTime/createdAt— Unix and ISO 8601 creation timelikeCount— likes on the commentreplyCount— replies TikTok reports for this comment (comments only)isPinnedByAuthor— pinned by the video creatorisLikedByAuthor— hearted by the video creatorisReply— true on reply rowsreplyToCommentId— root comment ID (reply rows)replyToReplyId— the reply being answered (nested replies)replyToUsername/replyToNickname/replyToUserId— who the reply answersthreadId— TikTok's thread identifier for the reply chainlanguage— detected comment languageisTranslatable— TikTok offers a translationshareUrl— share link that opens the commentuser.id/user.secUid/user.username/user.displayName/user.avatarUrl— commenter detailsuser.verified— present (true) when the commenter carries a verification badgeuser.region/user.bio— commenter country/region code and profile bio (only withincludeCommenterDetails)user.followerCount/user.followingCount/user.heartCount/user.videoCount— exact commenter stats (only withincludeCommenterStats)images— raw image list for image commentsstickers— raw sticker data for sticker commentslabels/textExtra— raw TikTok annotations (mentions, hashtags, labels)video— caption and stats of the source video (only withincludeVideoMetadata)scrapedAt— ISO 8601 collection time
Use cases
- Sentiment & topic analysis — build comment corpora per video, per creator or per campaign
- Creator engagement audits — pinned and creator-hearted comments surface the conversations a creator endorses
- Reply-thread research — reconstruct who answered whom with
replyToCommentId/replyToReplyId - Brand monitoring — sweep a profile's newest videos and catch complaints or questions early
- Moderation exports — pull full threads into CSV/JSON for review tooling
- Academic research — comment and reply networks with exact timestamps and stable IDs
FAQ
Do I need a TikTok account, cookies or a proxy? No. The actor reads TikTok's public comment data anonymously — no login, no cookies, no proxy setup. Pacing and retries are handled automatically.
How many comments can I get from one video?
As many as TikTok serves. The actor keeps walking the comment list past the point where a basic scraper stops. With deepWalk it reads TikTok's app-style view of the list, which exposes far more comments on many videos (for one video: ~42 via the standard walk, 131–160 via the app view), and restores image and sticker data from the standard view for each comment. Coverage still varies by network exit and by how many comments TikTok filters (spam, deleted, region-restricted) or withholds from anonymous readers, and the count shown in the app is live and can change during a run. The actor never invents rows.
How complete are reply threads? Replies are fetched per comment with their own cursor walk and capped only by your inputs. A thread with thousands of replies is collected across pages until it ends or your cap is reached.
What happens with deleted, private or comment-disabled videos? Deleted, private and nonexistent videos are detected from the video page and reported as unavailable in the status message; videos that exist but have no (or disabled) comments are reported as empty. Either way the actor emits no rows for that video and moves on.
Can I sort or filter comments?
Sorting and date filters are not available: TikTok returns comments in its own engagement-based ranking order and ignores sort/date parameters, so the actor offers none instead of silently dropping rows. You can trim by likes with minLikes — comments and replies below the threshold are left out; keyword filtering is best done in your own pipeline on the exported text.
How do I get commenter details and follower counts?
Two optional toggles. includeCommenterDetails adds the commenter's region code and bio (user.region, user.bio). includeCommenterStats adds exact follower, following, heart and video counts (user.followerCount, …) by looking up each unique commenter's public profile once; private or banned accounts are omitted, never guessed, and maxCommenterLookups caps how many commenters are enriched per run.
Can comments be translated?
No. TikTok's payload carries no translated text and the translation endpoint requires signed requests; the actor exports the original text plus language and isTranslatable for downstream translation.
Why do some comments have no text, and do media URLs expire?
Image-only and sticker-only comments have no text; their attachments are in images / stickers. Avatar and sticker URLs are signed TikTok CDN links that work when exported but expire after roughly a day or two — use commentId, user.username, shareUrl and postUrl as the durable keys.
Is this affiliated with TikTok? No. This is an independent, third-party actor that reads TikTok's publicly available comment data; it is not affiliated with, endorsed by, or operated by TikTok.
Python quickstart
Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.
Source build 5xR7gMTgKlauNkvWC. Documentation is regenerated from the default published build; private drafts are not included.