TikTok Post & Slideshow Detail Scraper
Fetch full metadata for any TikTok video or photo-carousel post by URL or ID: engagement stats, author snapshot, music details, hashtags, mentions, and signed media URLs.
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 |
|---|---|---|---|
mode | string | optional | What to scrape: individual posts, a profile's newest posts, or comment threads on posts. |
postUrls | array | optional | TikTok video/photo URLs, /v/ share links, embed links, vm.tiktok.com or vt.tiktok.com short links, or bare numeric post IDs. Duplicates are scraped once. |
postIds | array | optional | Numeric TikTok post IDs (15-20 digits). Use this instead of, or in addition to, postUrls. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | optional | What to scrape: individual posts, a profile's newest posts, or comment threads on posts. |
postUrls | array | optional | TikTok video/photo URLs, /v/ share links, embed links, vm.tiktok.com or vt.tiktok.com short links, or bare numeric post IDs. Duplicates are scraped once. |
postIds | array | optional | Numeric TikTok post IDs (15-20 digits). Use this instead of, or in addition to, postUrls. |
profiles | array | optional | TikTok usernames (@handle), profile URLs, or bare handles. Profiles mode returns up to 500 newest posts per profile; comments mode can use them as comment targets. |
maxItems | integer | optional | Global cap on output rows. Posts mode counts posts; profiles mode counts posts; comments mode counts comments and replies. Status rows do not count. |
maxDetail | integer | optional | How many posts get the slower page/detail enrichment (caption language, collect/repost counts, video tracks). Remaining posts use the fast embed record. Set to 1 for the smallest daily-test run. |
maxCommentsPerPost | integer | optional | Maximum comments plus replies to keep for each post in comments mode, or to attach to each post when Include comments is on. |
includeReplies | boolean | optional | Fetch the reply thread under each root comment and include replies with their parent. |
includeComments | boolean | optional | In posts/profiles mode, attach a comments array to each post. In comments mode, emit root comment rows (comments mode enables this automatically when both comment toggles are off). |
proxyConfiguration | object | optional | Optional. Leave empty to run directly; a proxy is not required. The actor falls back to an Apify datacenter proxy on a block signal. |
includeMediaUrls | boolean | optional | Include signed video, cover, music, and slideshow image URLs plus mediaUrlExpiresAt. They typically expire in about 48 hours. |
validateMediaUrls | boolean | optional | Check the main media URL with a GET Range request (TikTok's CDN rejects HEAD) and add mediaUrlAccessible. Adds latency. |
includeAuthorStats | boolean | optional | Include follower, following, heart, and video counts in author and authorStats. |
includeHashtags | boolean | optional | Include the hashtags array extracted from the caption. |
includeMentions | boolean | optional | Include the mentions array extracted from the caption with text offsets. |
includeSubtitles | boolean | optional | Include video.subtitleInfos, video.bitrateInfo, and video.volumeInfo (detail path only). |
includeRawFields | boolean | optional | Include item_control, contents, effectStickers, and stickersOnItem from the detail payload. Legacy includeEffectStickers/includeItemControl/includeContents inputs map here. |
Download the published input schema
View complete JSON
{
"description": "Scrape TikTok posts, profiles, and comment threads without cookies. Paste post URLs or IDs, profile handles, or both.",
"properties": {
"includeAuthorStats": {
"default": true,
"description": "Include follower, following, heart, and video counts in author and authorStats.",
"prefill": true,
"title": "Include author stats",
"type": "boolean"
},
"includeComments": {
"default": false,
"description": "In posts/profiles mode, attach a comments array to each post. In comments mode, emit root comment rows (comments mode enables this automatically when both comment toggles are off).",
"prefill": false,
"title": "Include comments",
"type": "boolean"
},
"includeHashtags": {
"default": true,
"description": "Include the hashtags array extracted from the caption.",
"prefill": true,
"title": "Include hashtags",
"type": "boolean"
},
"includeMediaUrls": {
"default": true,
"description": "Include signed video, cover, music, and slideshow image URLs plus mediaUrlExpiresAt. They typically expire in about 48 hours.",
"prefill": true,
"title": "Include media URLs",
"type": "boolean"
},
"includeMentions": {
"default": true,
"description": "Include the mentions array extracted from the caption with text offsets.",
"prefill": true,
"title": "Include mentions",
"type": "boolean"
},
"includeRawFields": {
"default": false,
"description": "Include item_control, contents, effectStickers, and stickersOnItem from the detail payload. Legacy includeEffectStickers/includeItemControl/includeContents inputs map here.",
"prefill": false,
"title": "Include raw TikTok fields",
"type": "boolean"
},
"includeReplies": {
"default": false,
"description": "Fetch the reply thread under each root comment and include replies with their parent.",
"prefill": false,
"title": "Include replies",
"type": "boolean"
},
"includeSubtitles": {
"default": false,
"description": "Include video.subtitleInfos, video.bitrateInfo, and video.volumeInfo (detail path only).",
"prefill": false,
"title": "Include subtitle and bitrate tracks",
"type": "boolean"
},
"maxCommentsPerPost": {
"default": 100,
"description": "Maximum comments plus replies to keep for each post in comments mode, or to attach to each post when Include comments is on.",
"maximum": 1000,
"minimum": 1,
"prefill": 100,
"title": "Max comments per post",
"type": "integer"
},
"maxDetail": {
"default": 50,
"description": "How many posts get the slower page/detail enrichment (caption language, collect/repost counts, video tracks). Remaining posts use the fast embed record. Set to 1 for the smallest daily-test run.",
"maximum": 300,
"minimum": 1,
"prefill": 1,
"title": "Max detail lookups",
"type": "integer"
},
"maxItems": {
"default": 100,
"description": "Global cap on output rows. Posts mode counts posts; profiles mode counts posts; comments mode counts comments and replies. Status rows do not count.",
"maximum": 1000,
"minimum": 1,
"prefill": 1,
"title": "Max rows",
"type": "integer"
},
"mode": {
"default": "posts",
"description": "What to scrape: individual posts, a profile's newest posts, or comment threads on posts.",
"editor": "select",
"enum": [
"posts",
"profiles",
"comments"
],
"enumTitles": [
"Posts by URL or ID",
"Profiles (newest posts)",
"Comments and replies"
],
"prefill": "posts",
"title": "Mode",
"type": "string"
},
"postIds": {
"description": "Numeric TikTok post IDs (15-20 digits). Use this instead of, or in addition to, postUrls.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Post IDs",
"type": "array"
},
"postUrls": {
"description": "TikTok video/photo URLs, /v/ share links, embed links, vm.tiktok.com or vt.tiktok.com short links, or bare numeric post IDs. Duplicates are scraped once.",
"editor": "stringList",
"items": {
"type": "string"
},
"prefill": [
"https://www.tiktok.com/@khaby.lame/video/7574844184952081686"
],
"title": "Post URLs or IDs",
"type": "array"
},
"profiles": {
"description": "TikTok usernames (@handle), profile URLs, or bare handles. Profiles mode returns up to 500 newest posts per profile; comments mode can use them as comment targets.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Profiles",
"type": "array"
},
"proxyConfiguration": {
"description": "Optional. Leave empty to run directly; a proxy is not required. The actor falls back to an Apify datacenter proxy on a block signal.",
"editor": "proxy",
"title": "Proxy configuration",
"type": "object"
},
"validateMediaUrls": {
"default": false,
"description": "Check the main media URL with a GET Range request (TikTok's CDN rejects HEAD) and add mediaUrlAccessible. Adds latency.",
"prefill": false,
"title": "Validate media URLs",
"type": "boolean"
}
},
"required": [],
"schemaVersion": 1,
"title": "TikTok Post Scraper 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 |
|---|---|---|---|
dataset | string | optional | All records: posts, comments/replies, and status rows. Use the dataset views to switch between them. |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"description": "Post rows with engagement stats, author snapshot, music, media, hashtags/mentions; comment rows with replies; and explicit status rows for unavailable inputs.",
"properties": {
"dataset": {
"description": "All records: posts, comments/replies, and status rows. Use the dataset views to switch between them.",
"template": "{{links.apiDefaultDatasetUrl}}/items",
"title": "Dataset",
"type": "string"
}
},
"title": "TikTok Post Scraper Output"
}
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": {
"AIGCDescription": {
"title": "AIGC Description",
"type": "string"
},
"adLabelVersion": {
"title": "Ad Label Version",
"type": "integer"
},
"author": {
"description": "Creator snapshot at scrape time (legacy flat stats included)",
"title": "Author",
"type": "object"
},
"authorStats": {
"description": "Grouped follower/following/heart/video counts",
"properties": {
"followerCount": {
"type": "integer"
},
"followingCount": {
"type": "integer"
},
"heartCount": {
"type": "integer"
},
"videoCount": {
"type": "integer"
}
},
"title": "Author Stats",
"type": "object"
},
"caption": {
"description": "Post caption including hashtags and mentions",
"title": "Caption",
"type": "string"
},
"channelTags": {
"items": {
"type": "string"
},
"title": "Channel Tags",
"type": "array"
},
"collectCount": {
"description": "Legacy flat collect count",
"title": "Collect Count",
"type": "integer"
},
"commentCount": {
"description": "Legacy flat comment count",
"title": "Comment Count",
"type": "integer"
},
"commentId": {
"title": "Comment ID",
"type": "string"
},
"commentStatus": {
"description": "Legacy flat flag (0=all, 1=friends, 2=none)",
"title": "Comment Status",
"type": "integer"
},
"comments": {
"description": "Comments attached to a post row, each optionally carrying a replies array",
"items": {
"type": "object"
},
"title": "Comments",
"type": "array"
},
"contents": {
"title": "Contents",
"type": "array"
},
"createTime": {
"description": "Unix timestamp (seconds) when the post was created",
"title": "Create Time (Unix)",
"type": "integer"
},
"createdAt": {
"description": "ISO 8601 UTC datetime when the post was created",
"title": "Created At",
"type": "string"
},
"diversificationLabels": {
"items": {
"type": "string"
},
"title": "Diversification Labels",
"type": "array"
},
"duetEnabled": {
"description": "Legacy flat flag",
"title": "Duet Enabled",
"type": "boolean"
},
"effectStickers": {
"title": "Effect Stickers",
"type": "array"
},
"flags": {
"description": "Grouped visibility, interaction, ad, and AI flags",
"title": "Post Flags",
"type": "object"
},
"forFriend": {
"description": "Legacy flat flag",
"title": "For Friend",
"type": "boolean"
},
"hashtags": {
"items": {
"type": "object"
},
"title": "Hashtags",
"type": "array"
},
"httpStatus": {
"description": "Last HTTP status observed for a failed input",
"title": "HTTP Status",
"type": "integer"
},
"images": {
"description": "Ordered carousel images with ordinal, dimensions, and signed urls",
"items": {
"type": "object"
},
"title": "Slideshow Images",
"type": "array"
},
"input": {
"description": "The original input that produced a status row",
"title": "Input",
"type": "string"
},
"isAd": {
"description": "Legacy flat flag",
"title": "Is Ad",
"type": "boolean"
},
"isAigc": {
"description": "Legacy flat flag",
"title": "Is AIGC",
"type": "boolean"
},
"isECVideo": {
"description": "Legacy flat flag",
"title": "Is E-Commerce Video",
"type": "boolean"
},
"isLikedByAuthor": {
"title": "Liked By Author",
"type": "boolean"
},
"isPinned": {
"description": "Whether the profile has pinned this post",
"title": "Is Pinned",
"type": "boolean"
},
"isPinnedByAuthor": {
"title": "Pinned By Author",
"type": "boolean"
},
"isReply": {
"title": "Is Reply",
"type": "boolean"
},
"item_control": {
"title": "Item Control",
"type": "object"
},
"language": {
"title": "Language",
"type": "string"
},
"likeCount": {
"description": "Legacy flat like count",
"title": "Like Count",
"type": "integer"
},
"locationCreated": {
"description": "Creator-set ISO country code",
"title": "Location Created",
"type": "string"
},
"mediaUrlAccessible": {
"description": "Result of the Range GET probe when validateMediaUrls is on",
"title": "Media URL Accessible",
"type": "boolean"
},
"mediaUrlExpiresAt": {
"description": "ISO 8601 UTC expiry of the signed media URLs (~48 hours)",
"title": "Media URL Expires At",
"type": "string"
},
"mentions": {
"items": {
"type": "object"
},
"title": "Mentions",
"type": "array"
},
"message": {
"description": "Human-readable reason for a status row",
"title": "Message",
"type": "string"
},
"music": {
"title": "Music",
"type": "object"
},
"originalItem": {
"description": "Legacy flat flag",
"title": "Original Item",
"type": "boolean"
},
"playCount": {
"description": "Legacy flat play count",
"title": "Play Count",
"type": "integer"
},
"poi": {
"title": "Point of Interest",
"type": "object"
},
"position": {
"description": "1-based position within the profile feed",
"title": "Position",
"type": "integer"
},
"postId": {
"description": "TikTok's unique post/video ID (string to preserve 64-bit precision)",
"title": "Post ID",
"type": "string"
},
"postType": {
"description": "video or slideshow",
"title": "Post Type",
"type": "string"
},
"postUrl": {
"description": "Canonical TikTok post URL",
"title": "Post URL",
"type": "string"
},
"privateItem": {
"description": "Legacy flat flag",
"title": "Private Item",
"type": "boolean"
},
"profileUsername": {
"description": "Profile that produced this row in profiles mode",
"title": "Profile Username",
"type": "string"
},
"recordType": {
"description": "post, comment, reply, or status",
"title": "Record Type",
"type": "string"
},
"replyCount": {
"title": "Reply Count",
"type": "integer"
},
"replyToCommentId": {
"title": "Reply To Comment ID",
"type": "string"
},
"repostCount": {
"description": "Legacy flat repost count",
"title": "Repost Count",
"type": "integer"
},
"scrapedAt": {
"description": "ISO 8601 UTC timestamp when this row was built",
"title": "Scraped At",
"type": "string"
},
"shareCount": {
"description": "Legacy flat share count",
"title": "Share Count",
"type": "integer"
},
"shareEnabled": {
"description": "Legacy flat flag",
"title": "Share Enabled",
"type": "boolean"
},
"source": {
"description": "Extraction path: embed, detail, ssr, profile, comment_api, or short",
"title": "Source",
"type": "string"
},
"stats": {
"description": "Grouped engagement counts",
"properties": {
"collectCount": {
"type": "integer"
},
"commentCount": {
"type": "integer"
},
"likeCount": {
"type": "integer"
},
"playCount": {
"type": "integer"
},
"repostCount": {
"type": "integer"
},
"shareCount": {
"type": "integer"
}
},
"title": "Post Stats",
"type": "object"
},
"status": {
"description": "Diagnostic status for a failed input: not_found, private, region, or blocked",
"title": "Status",
"type": "string"
},
"stickersOnItem": {
"title": "Stickers On Item",
"type": "array"
},
"stitchEnabled": {
"description": "Legacy flat flag",
"title": "Stitch Enabled",
"type": "boolean"
},
"text": {
"title": "Comment Text",
"type": "string"
},
"textExtra": {
"title": "Text Extra",
"type": "array"
},
"textLanguage": {
"description": "Detected caption language code (detail path)",
"title": "Text Language",
"type": "string"
},
"threadId": {
"title": "Thread ID",
"type": "string"
},
"user": {
"title": "Commenter",
"type": "object"
},
"video": {
"title": "Video",
"type": "object"
},
"viewerRegion": {
"description": "Egress region TikTok inferred for the request; not the post's location",
"title": "Request Region",
"type": "string"
},
"warnInfo": {
"title": "Warn Info",
"type": "array"
}
},
"title": "TikTok Posts, Profiles & Comments",
"views": {
"comments": {
"description": "Comment rows emitted by comments mode. Reply rows carry isReply=true.",
"display": {
"component": "table",
"properties": {
"commentId": {
"format": "text",
"label": "Comment ID"
},
"createdAt": {
"format": "text",
"label": "Created At"
},
"isReply": {
"format": "boolean",
"label": "Is Reply"
},
"language": {
"format": "text",
"label": "Language"
},
"likeCount": {
"format": "number",
"label": "Likes"
},
"postId": {
"format": "text",
"label": "Post ID"
},
"postUrl": {
"format": "link",
"label": "Post URL"
},
"recordType": {
"format": "text",
"label": "Type"
},
"replyCount": {
"format": "number",
"label": "Replies"
},
"scrapedAt": {
"format": "text",
"label": "Scraped At"
},
"source": {
"format": "text",
"label": "Source"
},
"text": {
"format": "text",
"label": "Text"
},
"user": {
"format": "object",
"label": "User"
}
}
},
"title": "Comments & Replies",
"transformation": {
"fields": [
"recordType",
"postId",
"postUrl",
"commentId",
"text",
"user",
"likeCount",
"replyCount",
"isReply",
"createdAt",
"language",
"source",
"scrapedAt"
]
}
},
"overview": {
"description": "One row per post with engagement metrics, author snapshot, and the extraction source.",
"display": {
"component": "table",
"properties": {
"author": {
"format": "object",
"label": "Author"
},
"caption": {
"format": "text",
"label": "Caption"
},
"commentCount": {
"format": "number",
"label": "Comments"
},
"createdAt": {
"format": "text",
"label": "Created At"
},
"likeCount": {
"format": "number",
"label": "Likes"
},
"playCount": {
"format": "number",
"label": "Plays"
},
"postId": {
"format": "text",
"label": "Post ID"
},
"postType": {
"format": "text",
"label": "Type"
},
"postUrl": {
"format": "link",
"label": "Post URL"
},
"recordType": {
"format": "text",
"label": "Record"
},
"scrapedAt": {
"format": "text",
"label": "Scraped At"
},
"shareCount": {
"format": "number",
"label": "Shares"
},
"source": {
"format": "text",
"label": "Source"
}
}
},
"title": "Posts Overview",
"transformation": {
"fields": [
"postId",
"postUrl",
"postType",
"caption",
"createdAt",
"playCount",
"likeCount",
"commentCount",
"shareCount",
"author",
"recordType",
"source",
"scrapedAt"
]
}
},
"status": {
"description": "Explicit not_found/private/region/blocked status rows. These do not count toward Max rows.",
"display": {
"component": "table",
"properties": {
"httpStatus": {
"format": "number",
"label": "HTTP"
},
"input": {
"format": "text",
"label": "Input"
},
"message": {
"format": "text",
"label": "Message"
},
"postId": {
"format": "text",
"label": "Post ID"
},
"recordType": {
"format": "text",
"label": "Record"
},
"scrapedAt": {
"format": "text",
"label": "Scraped At"
},
"source": {
"format": "text",
"label": "Source"
},
"status": {
"format": "text",
"label": "Status"
}
}
},
"title": "Unavailable Inputs",
"transformation": {
"fields": [
"recordType",
"status",
"input",
"postId",
"message",
"httpStatus",
"source",
"scrapedAt"
]
}
}
}
}
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 Post Scraper
Paste a TikTok link, a bare post ID, or a profile handle and get structured post data back: engagement counts, the creator's snapshot at scrape time, the sound, every hashtag and @mention, carousel images, and signed media URLs. The actor also reads comment threads, including replies, and can walk a profile's newest posts. No TikTok account, cookies, or login are required.
Three ways to use it
| Mode | What you provide | What you get |
|---|---|---|
| Posts | Video/photo URLs, share links, or numeric IDs | One row per post |
| Profiles | Handles, @names, or profile URLs | One row per newest post, up to 500 per profile |
| Comments | Post URLs/IDs and/or profiles | One row per comment and reply, up to 1,000 per post |
The default run is the smallest useful one: one known slideshow post, embed-first, no comments.
What makes it useful
- Fast first, rich when asked. Every post starts on TikTok's embed surface (~0.7 s). The slower page/detail path runs only for
maxDetailposts, so bulk runs stay quick while the first rows still carry language, collect/repost counts, and video tracks. - Slideshows stay slideshows. Carousel posts are detected from both the embed shape (
imagePostInfo.displayImages) and the detail shape (imagePost.images), so the images array is not lost when the fast path misses. - Bare IDs work. IDs are opened with a safe placeholder username instead of the
/video/<id>path that redirects to a 404. - No silent holes. Deleted, private, region-locked, or blocked inputs become explicit
recordType: "status"rows with a reason, not an empty dataset. - Honest media checks. TikTok's video CDN rejects
HEAD; the optional URL check uses aGET Rangerequest and reports what actually answered. - Deduplicated. The same post ID from a URL, a short link, and an ID list is scraped once. Comments are deduplicated by comment ID.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
mode |
select | posts |
posts, profiles, or comments |
postUrls |
array | one slideshow prefill | Video/photo URLs, /v/ and /share/ links, embed links, vm.tiktok.com/vt.tiktok.com/tiktok.com/t/ short links, or bare IDs |
postIds |
array | – | 15–20 digit numeric IDs |
profiles |
array | – | @handle, profile URL, or bare handle; up to 500 newest posts per profile |
maxItems |
integer 1–1000 | 100 |
Global row cap. Posts/profiles count posts; comments counts comments + replies |
maxDetail |
integer 1–300 | 50 |
How many posts get the slower page/detail enrichment |
maxCommentsPerPost |
integer 1–1000 | 100 |
Comments + replies kept per post |
includeReplies |
boolean | false |
Fetch reply threads under root comments |
includeComments |
boolean | false |
Attach a comments array in posts/profiles mode; emit root comment rows in comments mode |
proxyConfiguration |
object | – | Optional. Direct requests are the default; AUTO datacenter is used on a block signal |
includeMediaUrls |
boolean | true |
Signed video/cover/music/image URLs and mediaUrlExpiresAt |
validateMediaUrls |
boolean | false |
Range GET probe → mediaUrlAccessible |
includeAuthorStats |
boolean | true |
authorStats and legacy author counts |
includeHashtags |
boolean | true |
Hashtags array |
includeMentions |
boolean | true |
Mentions array with offsets |
includeSubtitles |
boolean | false |
video.subtitleInfos, bitrateInfo, volumeInfo |
includeRawFields |
boolean | false |
item_control, contents, effectStickers, stickersOnItem |
Examples
Scrape one video and one carousel, with detail enrichment:
{
"mode": "posts",
"postUrls": [
"https://www.tiktok.com/@natgeo/video/7683891628230315295",
"https://www.tiktok.com/@nba/photo/7690755132400618783"
],
"maxItems": 2,
"maxDetail": 2
}
Walk a profile's newest posts:
{
"mode": "profiles",
"profiles": ["natgeo"],
"maxItems": 50,
"maxDetail": 20
}
Read comments and replies from a post:
{
"mode": "comments",
"postUrls": ["https://www.tiktok.com/@natgeo/video/7683891628230315295"],
"maxCommentsPerPost": 200,
"includeReplies": true,
"maxItems": 200
}
Bulk short links and IDs:
{
"mode": "posts",
"postUrls": ["https://vm.tiktok.com/ZMabc123/"],
"postIds": ["7574844184952081686"],
"maxItems": 100
}
Output
Every record is omit-empty: absent fields are left out rather than returned as null, "", or an empty array.
Post rows (recordType: "post")
postId,postType(video/slideshow),postUrlcaption,textLanguage,createTime,createdAt,locationCreated,viewerRegionauthor— id, secUid, username, displayName, bio, verified, privateAccount, avatarUrl, roomId (legacy counts also live here)authorStats— followerCount, followingCount, heartCount, videoCountstats— playCount, likeCount, commentCount, shareCount, collectCount, repostCount (also kept as flat legacy fields)flags— stitchEnabled, duetEnabled, shareEnabled, commentStatus, isAd, isAigc, isECVideo, privateItem, forFriend, originalItem, plus labels when present (also kept flat)music— id, title, authorName, album, original, duration, shootDuration, licensing flags, dspLinks, playUrl, coverUrlvideo— width, height, duration, ratio, definition, bitrate, codecType, format, size, videoQuality, playUrl, downloadAddr, cover, originCover, dynamicCover, optional subtitle/bitrate/volume tracksimages— ordered carousel objects:ordinal,width,height,urlListhashtags,mentionsmediaUrlExpiresAt, optionalmediaUrlAccessiblesource(embed,detail,ssr, orprofile),scrapedAt,recordType- Profiles mode adds
profileUsername,position, andisPinnedwhen the profile pinned the post commentswhenincludeCommentsis on: root comments, each optionally carrying arepliesarray
Comment rows (recordType: "comment" or "reply")
commentId, postId, postUrl, text, createTime, createdAt, likeCount, replyCount, isPinnedByAuthor, isLikedByAuthor, isTranslatable, language, isReply, replyToCommentId, threadId, user (id, secUid, username, displayName, avatarUrl, optional verified), images, textExtra, optional share link/stickers/labels, source, scrapedAt.
Status rows (recordType: "status")
status is one of not_found, private, region, or blocked, plus input, optional postId, message, httpStatus, source, and scrapedAt. Status rows are diagnostics and do not count toward maxItems.
Limits and behaviour
- Posts: up to
maxItemsrows (1–1000).maxDetailcaps the slower page/detail lookups (1–300). - Profiles: up to 500 newest posts per profile and
maxItemsrows overall. The profile feed normally comes from TikTok's itemList; if that XHR returns an empty body, the actor retries and then falls back to the creator itemList endpoint. - Comments: up to 1,000 comment + reply rows per post. TikTok's
totalcounter is not used as a progress guarantee; the actor follows the cursor and stops after repeated empty windows. - Pacing: requests are spaced 1.2–2.0 s apart. HTTP 429 and 503 responses are retried with a 1.5–4.5 s backoff.
- Media URLs are signed and typically expire in about 48 hours.
mediaUrlExpiresAttells you when. - Private / deleted / region-locked posts cannot be read without cookies; they produce a status row.
- Comments on deleted posts may look identical to a post with no comments; the actor reports the post status it observed.
FAQ
Do I need a TikTok account or cookies? No. The actor uses public embed pages, the public video page, and unsigned comment endpoints.
Is a proxy required? No. Direct requests are the primary path. If TikTok blocks the request, the actor retries with an Apify datacenter proxy. A proxy is exposed only for users who want to supply their own.
Why do some rows have more fields than others?
The embed path is fast but omits a few detail-only values (caption language, collect/repost counts, video tracks). Raise maxDetail to enrich more posts; the actor never fabricates a field it could not read.
How do I get only slideshows?
Provide slideshow URLs or IDs. Slideshow rows have postType: "slideshow" and an ordered images array. There is no separate slideshow-only mode because the same post-ID path covers videos and carousels.
Why is a row missing? Check the status view. Inputs that cannot be parsed, resolved, or read are reported there instead of disappearing.
Can I attach comments to post rows?
Yes. Set includeComments: true in posts or profiles mode; set includeReplies too if you want reply threads nested under each root comment.
Is this affiliated with TikTok? No. This is an independent, third-party actor that reads publicly viewable TikTok content.
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 Ua3QPyCof7v3HFAEk. Documentation is regenerated from the default published build; private drafts are not included.