Vexaloom Labs

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.

FieldTypeRequiredDescription
postUrlsarrayoptionalTikTok video or photo URLs to scrape comments from (e.g. https://www.tiktok.com/@user/video/123...).
postIdsarrayoptionalNumeric TikTok video IDs (15-20 digits) as an alternative to URLs.
profilesarrayoptionalTikTok usernames or profile URLs. The actor scrapes comments from their newest videos, up to 'Max videos per profile'.
Show all input fields
FieldTypeRequiredDescription
postUrlsarrayoptionalTikTok video or photo URLs to scrape comments from (e.g. https://www.tiktok.com/@user/video/123...).
postIdsarrayoptionalNumeric TikTok video IDs (15-20 digits) as an alternative to URLs.
profilesarrayoptionalTikTok usernames or profile URLs. The actor scrapes comments from their newest videos, up to 'Max videos per profile'.
maxVideosPerProfileintegeroptionalHow many of each profile's newest videos to scrape comments from.
maxCommentsPerPostintegeroptionalMaximum number of rows per video, counting replies when 'Include replies' is on. The actor walks the comment section as deep as TikTok serves it.
includeRepliesbooleanoptionalFetch the reply thread under each root comment and emit each reply as its own row right after its parent.
maxRepliesPerCommentintegeroptionalCap the replies fetched for any single root comment. Set to 0 for all replies (still bounded by 'Max comment rows per video').
maxItemsintegeroptionalGlobal cap on the number of rows in the run (comments + replies). Set to 0 for no global cap.
minLikesintegeroptionalOnly keep comments and replies with at least this many likes. Comments below the threshold are skipped before their replies are fetched.
includeVideoMetadatabooleanoptionalAdd a 'video' object (caption, author, view/like/comment counts) to every row.
includeCommenterDetailsbooleanoptionalAdd 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.
includeCommenterStatsbooleanoptionalAdd 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.
maxCommenterLookupsintegeroptionalCap on how many commenters are enriched when 'Include commenter follower counts' is on. Set to 0 for no cap.
deepWalkbooleanoptionalRead 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.

FieldTypeRequiredDescription
commentIdstringrequiredUnique numeric ID of the comment or reply.
postIdstringrequiredNumeric ID of the TikTok video this comment belongs to.
postUrlstringrequiredURL of the TikTok video.
rowTypestringoptional'comment' for top-level comments, 'reply' for replies.
textstringoptionalThe text content of the comment or reply.
createdAtstringrequiredISO 8601 timestamp when the comment was posted.
likeCountstringrequiredNumber of likes on the comment.
replyCountstringrequiredTotal number of direct replies to this comment.
isPinnedByAuthorstringrequiredTrue if the comment is pinned by the video author.
isLikedByAuthorstringrequiredTrue if the video author has liked this comment.
isReplystringrequiredTrue when this row is a reply to another comment rather than a top-level comment.
replyToCommentIdstringoptionalID of the root comment this row replies to. Present only on reply rows.
replyToReplyIdstringoptionalFor nested replies, the ID of the reply this row answers.
replyToUsernamestringoptionalHandle of the comment/reply being answered (reply rows).
replyToNicknamestringoptionalDisplay name of the comment/reply being answered (reply rows).
replyToUserIdstringoptionalNumeric user ID of the comment/reply being answered (reply rows).
threadIdstringoptionalID grouping a root comment with its replies, when TikTok provides one.
languagestringoptionalDetected language code of the comment (e.g. 'en', 'es'). May be absent.
isTranslatablestringoptionalWhether TikTok offers a translation for this comment.
shareUrlstringoptionalTikTok share link that opens this comment.
scrapedAtstringoptionalISO 8601 timestamp when the row was collected.
videostringoptionalCaption, 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 (and replyToReplyId for 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)
  • deepWalk mode 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 — comment for top-level comments, reply for replies
  • commentId — unique TikTok comment ID
  • postId — ID of the video the comment belongs to
  • postUrl — URL of the video
  • text — comment text (absent on image/sticker-only comments)
  • createTime / createdAt — Unix and ISO 8601 creation time
  • likeCount — likes on the comment
  • replyCount — replies TikTok reports for this comment (comments only)
  • isPinnedByAuthor — pinned by the video creator
  • isLikedByAuthor — hearted by the video creator
  • isReply — true on reply rows
  • replyToCommentId — root comment ID (reply rows)
  • replyToReplyId — the reply being answered (nested replies)
  • replyToUsername / replyToNickname / replyToUserId — who the reply answers
  • threadId — TikTok's thread identifier for the reply chain
  • language — detected comment language
  • isTranslatable — TikTok offers a translation
  • shareUrl — share link that opens the comment
  • user.id / user.secUid / user.username / user.displayName / user.avatarUrl — commenter details
  • user.verified — present (true) when the commenter carries a verification badge
  • user.region / user.bio — commenter country/region code and profile bio (only with includeCommenterDetails)
  • user.followerCount / user.followingCount / user.heartCount / user.videoCount — exact commenter stats (only with includeCommenterStats)
  • images — raw image list for image comments
  • stickers — raw sticker data for sticker comments
  • labels / textExtra — raw TikTok annotations (mentions, hashtags, labels)
  • video — caption and stats of the source video (only with includeVideoMetadata)
  • 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.

Open the step-by-step Python guide →

Source build 5xR7gMTgKlauNkvWC. Documentation is regenerated from the default published build; private drafts are not included.