Vexaloom Labs

TikTok Account Stats & Repost History Scraper

Look up TikTok accounts for follower/like/video stats, recent videos, and reposted content in one run. Optional session cookie unlocks a profile's full video history. No cookie required for account stats or reposts.

Input schema

Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.

FieldTypeRequiredDescription
usernamesarrayoptionalTikTok usernames to look up (with or without @). You can mix usernames and profile URLs, and list as many as you need in one run.
profileUrlsarrayoptionalFull TikTok profile URLs (e.g. https://www.tiktok.com/@khaby.lame). Can be used instead of or together with Usernames.
contentTypesarrayoptionalChoose which rows to emit for every account. 'profile' = account stats and metadata, 'videos' = the account's posts, 'reposts' = content the account re-shared, 'playlists' = the account's playlists (names, covers, video counts).
Show all input fields
FieldTypeRequiredDescription
usernamesarrayoptionalTikTok usernames to look up (with or without @). You can mix usernames and profile URLs, and list as many as you need in one run.
profileUrlsarrayoptionalFull TikTok profile URLs (e.g. https://www.tiktok.com/@khaby.lame). Can be used instead of or together with Usernames.
contentTypesarrayoptionalChoose which rows to emit for every account. 'profile' = account stats and metadata, 'videos' = the account's posts, 'reposts' = content the account re-shared, 'playlists' = the account's playlists (names, covers, video counts).
playlistUrlsarrayoptionalFull playlist URLs (e.g. https://www.tiktok.com/@natgeo/playlist/wildlife-7509464647364283178) to collect the videos inside those playlists. Independent of Usernames.
maxPostsPerProfileintegeroptionalMaximum number of post rows per account, combined across videos and reposts. 0 skips post collection entirely (useful for a fast stats-only run). Playlist rows are not counted.
maxItemsintegeroptionalGlobal cap on post rows for the whole run across all accounts (0 = no limit). Profile and playlist rows are not counted.
includeProfileInfobooleanoptionalWhen off, no profile rows are written even if 'profile' is selected above; only post rows are produced.
oldestPostDatestringoptionalSkip posts published before this date (UTC). Format: YYYY-MM-DD, e.g. 2026-01-01. Leave empty to collect the newest posts with no lower bound.
newestPostDatestringoptionalSkip posts published after this date (UTC). Format: YYYY-MM-DD, e.g. 2026-01-01. Leave empty to start from each account's most recent post.
includeLiveStatusbooleanoptionalAdds isLive and, when the account is live, the live room title, start time and viewer count to the profile row. Emitted only when TikTok reports the account's live status.
computedStatsbooleanoptionalAdds averagePlays, medianPlays and postsPerWeek to the profile row, computed over the videos fetched for that account in this run (the window is the returned set, not the full history).
onlyNewVideosbooleanoptionalWhen on, each account emits only the videos posted since the previous run of that same account. The newest video seen is remembered between runs in the actor's named key-value store, so scheduling the actor turns it into a new-video monitor. The first run for an account returns all videos up to Max Post Rows per Profile and seeds the state. Reposts and playlists are not filtered. If the stored state is ever lost, the next run behaves like a first run.
pinnedFirstbooleanoptionalWhen on, videos the account pinned to the top of its profile (TikTok's pinned posts) are emitted before the rest of the post rows collected in this run. Pinned videos also carry isPinned: true.

Download the published input schema

View complete JSON
{
  "description": "Look up TikTok accounts and get their stats, full video history, reposts, playlists and live status. No cookies or proxy setup required.",
  "properties": {
    "computedStats": {
      "default": false,
      "description": "Adds averagePlays, medianPlays and postsPerWeek to the profile row, computed over the videos fetched for that account in this run (the window is the returned set, not the full history).",
      "prefill": false,
      "title": "Add Derived Statistics",
      "type": "boolean"
    },
    "contentTypes": {
      "default": [
        "profile",
        "videos"
      ],
      "description": "Choose which rows to emit for every account. 'profile' = account stats and metadata, 'videos' = the account's posts, 'reposts' = content the account re-shared, 'playlists' = the account's playlists (names, covers, video counts).",
      "editor": "select",
      "items": {
        "enum": [
          "profile",
          "videos",
          "reposts",
          "playlists"
        ],
        "enumTitles": [
          "Profile info and stats",
          "Videos (full history)",
          "Reposts",
          "Playlists"
        ],
        "type": "string"
      },
      "prefill": [
        "profile",
        "videos",
        "reposts"
      ],
      "title": "What to collect per account",
      "type": "array"
    },
    "includeLiveStatus": {
      "default": true,
      "description": "Adds isLive and, when the account is live, the live room title, start time and viewer count to the profile row. Emitted only when TikTok reports the account's live status.",
      "prefill": true,
      "title": "Include Live Status",
      "type": "boolean"
    },
    "includeProfileInfo": {
      "default": true,
      "description": "When off, no profile rows are written even if 'profile' is selected above; only post rows are produced.",
      "prefill": true,
      "title": "Include Profile Info",
      "type": "boolean"
    },
    "maxItems": {
      "default": 0,
      "description": "Global cap on post rows for the whole run across all accounts (0 = no limit). Profile and playlist rows are not counted.",
      "maximum": 100000,
      "minimum": 0,
      "prefill": 0,
      "title": "Max Post Rows per Run",
      "type": "integer"
    },
    "maxPostsPerProfile": {
      "default": 30,
      "description": "Maximum number of post rows per account, combined across videos and reposts. 0 skips post collection entirely (useful for a fast stats-only run). Playlist rows are not counted.",
      "maximum": 500,
      "minimum": 0,
      "prefill": 10,
      "title": "Max Post Rows per Profile",
      "type": "integer"
    },
    "newestPostDate": {
      "default": "",
      "description": "Skip posts published after this date (UTC). Format: YYYY-MM-DD, e.g. 2026-01-01. Leave empty to start from each account's most recent post.",
      "editor": "textfield",
      "prefill": "",
      "title": "Only Posts Up To This Date (optional)",
      "type": "string"
    },
    "oldestPostDate": {
      "default": "",
      "description": "Skip posts published before this date (UTC). Format: YYYY-MM-DD, e.g. 2026-01-01. Leave empty to collect the newest posts with no lower bound.",
      "editor": "textfield",
      "prefill": "",
      "title": "Only Posts From This Date (optional)",
      "type": "string"
    },
    "onlyNewVideos": {
      "default": false,
      "description": "When on, each account emits only the videos posted since the previous run of that same account. The newest video seen is remembered between runs in the actor's named key-value store, so scheduling the actor turns it into a new-video monitor. The first run for an account returns all videos up to Max Post Rows per Profile and seeds the state. Reposts and playlists are not filtered. If the stored state is ever lost, the next run behaves like a first run.",
      "prefill": false,
      "title": "Only New Videos (monitoring)",
      "type": "boolean"
    },
    "pinnedFirst": {
      "default": false,
      "description": "When on, videos the account pinned to the top of its profile (TikTok's pinned posts) are emitted before the rest of the post rows collected in this run. Pinned videos also carry isPinned: true.",
      "prefill": false,
      "title": "Show Pinned Videos First",
      "type": "boolean"
    },
    "playlistUrls": {
      "description": "Full playlist URLs (e.g. https://www.tiktok.com/@natgeo/playlist/wildlife-7509464647364283178) to collect the videos inside those playlists. Independent of Usernames.",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "title": "Playlist URLs (optional)",
      "type": "array"
    },
    "profileUrls": {
      "description": "Full TikTok profile URLs (e.g. https://www.tiktok.com/@khaby.lame). Can be used instead of or together with Usernames.",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "title": "Profile URLs",
      "type": "array"
    },
    "usernames": {
      "description": "TikTok usernames to look up (with or without @). You can mix usernames and profile URLs, and list as many as you need in one run.",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "prefill": [
        "natgeo"
      ],
      "title": "TikTok Usernames",
      "type": "array"
    }
  },
  "required": [],
  "schemaVersion": 1,
  "title": "TikTok Account Stats & Repost History 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.

FieldTypeRequiredDescription
datastringoptionalDataset rows with a rowType discriminator: 'profile' for account stats, 'video'/'repost' for posts, 'playlist' for playlists.

Download the published output schema

View complete JSON
{
  "actorOutputSchemaVersion": 1,
  "description": "Account rows with exact stats and live status, video and repost rows with engagement metrics and media metadata, and playlist rows for the account's playlists.",
  "properties": {
    "data": {
      "description": "Dataset rows with a rowType discriminator: 'profile' for account stats, 'video'/'repost' for posts, 'playlist' for playlists.",
      "template": "{{links.apiDefaultDatasetUrl}}/items",
      "title": "Accounts, Posts & Playlists",
      "type": "string"
    }
  },
  "title": "TikTok Account Stats & Repost History 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": {
      "description": "Creator-provided disclosure text describing which parts of the post are AI-generated. Present on post rows when disclosed.",
      "title": "AI-Generated Content Description",
      "type": "string"
    },
    "UserStoryStatus": {
      "description": "TikTok Stories status flag. Present on profile rows when available.",
      "title": "User Story Status",
      "type": "integer"
    },
    "adLabelVersion": {
      "description": "Internal TikTok advertising-label version applied to this post. Present on post rows when the post carries an ad label.",
      "title": "Ad Label Version",
      "type": "integer"
    },
    "author": {
      "description": "Author snapshot at time of scraping. Present on post rows.",
      "properties": {
        "avatarUrl": {
          "title": "Avatar URL",
          "type": "string"
        },
        "bio": {
          "title": "Bio",
          "type": "string"
        },
        "displayName": {
          "title": "Display Name",
          "type": "string"
        },
        "followerCount": {
          "title": "Followers",
          "type": "integer"
        },
        "followingCount": {
          "title": "Following",
          "type": "integer"
        },
        "heartCount": {
          "title": "Hearts",
          "type": "integer"
        },
        "id": {
          "title": "User ID",
          "type": "string"
        },
        "privateAccount": {
          "title": "Private Account",
          "type": "boolean"
        },
        "roomId": {
          "title": "Live Room ID",
          "type": "string"
        },
        "secUid": {
          "title": "Secure UID",
          "type": "string"
        },
        "username": {
          "title": "Username",
          "type": "string"
        },
        "verified": {
          "title": "Verified",
          "type": "boolean"
        },
        "videoCount": {
          "title": "Videos",
          "type": "integer"
        }
      },
      "title": "Author",
      "type": "object"
    },
    "avatarLarger": {
      "description": "URL of the large avatar image. Present on profile rows.",
      "title": "Avatar (Large)",
      "type": "string"
    },
    "avatarMedium": {
      "description": "URL of the medium avatar image. Present on profile rows.",
      "title": "Avatar (Medium)",
      "type": "string"
    },
    "avatarThumb": {
      "description": "URL of the thumbnail avatar image. Present on profile rows.",
      "title": "Avatar (Thumbnail)",
      "type": "string"
    },
    "averagePlays": {
      "description": "Mean play count over the videos fetched for this account in this run (enabled by computedStats).",
      "title": "Average plays",
      "type": "number"
    },
    "bio": {
      "description": "Profile biography / signature text. Present on profile rows.",
      "title": "Bio",
      "type": "string"
    },
    "bioEmail": {
      "description": "Email address found in the profile bio text, when one is present.",
      "title": "Email in bio",
      "type": "string"
    },
    "bioLink": {
      "description": "URL in the profile bio link field. Present on profile rows when set.",
      "title": "Bio Link",
      "type": "string"
    },
    "caption": {
      "description": "Post caption/description text including hashtags and mentions. Present on post rows.",
      "title": "Caption",
      "type": "string"
    },
    "channelTags": {
      "description": "Content channel/category tags TikTok assigned to the post. Present on post rows when available.",
      "title": "Channel Tags",
      "type": "array"
    },
    "collectCount": {
      "description": "Number of times post was bookmarked/collected. Present on post rows.",
      "title": "Collect Count",
      "type": "integer"
    },
    "commentCount": {
      "description": "Number of comments. Present on post rows.",
      "title": "Comment Count",
      "type": "integer"
    },
    "commentSetting": {
      "description": "Who can comment on the user's posts (0=everyone, 1=friends, 2=no one). Present on profile rows.",
      "title": "Comment Setting",
      "type": "integer"
    },
    "commentStatus": {
      "description": "Raw TikTok comment-permission code for this post (0=everyone, 1=friends, 2=off, 3=followers). Present on post rows when available.",
      "title": "Comment Status",
      "type": "integer"
    },
    "commerceCategory": {
      "description": "TikTok business account category (e.g. 'Media & Entertainment') when the account has one.",
      "title": "Business category",
      "type": "string"
    },
    "contentKind": {
      "description": "Whether the post is the user's own content ('video') or a repost ('repost'). Present on post rows.",
      "title": "Content Kind",
      "type": "string"
    },
    "contents": {
      "description": "Structured caption segments (text/hashtag/mention parts) as returned by TikTok's content API. Present on post rows when available.",
      "title": "Contents",
      "type": "array"
    },
    "coverUrl": {
      "description": "Signed cover image URL for the playlist or media entity.",
      "title": "Cover URL",
      "type": "string"
    },
    "createTime": {
      "description": "Unix timestamp when the post was created. Present on post rows.",
      "title": "Create Time (Unix)",
      "type": "integer"
    },
    "createdAt": {
      "description": "ISO 8601 UTC datetime when the post was created. Present on post rows.",
      "title": "Created At",
      "type": "string"
    },
    "diggCount": {
      "description": "Number of posts liked by this user (from statsV2). Present on profile rows when available.",
      "title": "Digg Count",
      "type": "integer"
    },
    "displayName": {
      "description": "User's public display name / nickname. Present on profile rows.",
      "title": "Display Name",
      "type": "string"
    },
    "diversificationLabels": {
      "description": "TikTok content-category labels used for feed diversification. Present on post rows when available.",
      "title": "Diversification Labels",
      "type": "array"
    },
    "downloadSetting": {
      "description": "Whether others can download the user's videos. Present on profile rows.",
      "title": "Download Setting",
      "type": "integer"
    },
    "duetEnabled": {
      "description": "Whether duets are allowed for this post. Present on post rows.",
      "title": "Duet Enabled",
      "type": "boolean"
    },
    "duetSetting": {
      "description": "Who can duet the user's videos. Present on profile rows.",
      "title": "Duet Setting",
      "type": "integer"
    },
    "effectStickers": {
      "description": "Visual effects/filters applied to the post. Present on post rows when effects were used.",
      "title": "Effect Stickers",
      "type": "array"
    },
    "embedUrl": {
      "description": "Permanent, cookieless player link for the post (https://www.tiktok.com/embed/v2/<postId>). Opens the post in TikTok's embedded player in any browser with no account or cookies.",
      "title": "Embed URL",
      "type": "string"
    },
    "followerCount": {
      "description": "Number of followers (from statsV2). Present on profile rows.",
      "title": "Follower Count",
      "type": "integer"
    },
    "followingCount": {
      "description": "Number of accounts followed (from statsV2). Present on profile rows.",
      "title": "Following Count",
      "type": "integer"
    },
    "followingVisibility": {
      "description": "Who can see the user's following list (0=everyone, 1=friends, 2=no one). Present on profile rows.",
      "title": "Following Visibility",
      "type": "integer"
    },
    "forFriend": {
      "description": "Whether the post was published as friends-only. Present on post rows.",
      "title": "For Friends Only",
      "type": "boolean"
    },
    "hashtags": {
      "description": "Hashtags used in the post caption. Present on post rows when present.",
      "items": {
        "properties": {
          "id": {
            "title": "Hashtag ID",
            "type": "string"
          },
          "isCommerce": {
            "title": "Is Commerce",
            "type": "boolean"
          },
          "name": {
            "title": "Hashtag Name",
            "type": "string"
          }
        },
        "type": "object"
      },
      "title": "Hashtags",
      "type": "array"
    },
    "heartCount": {
      "description": "Total likes/hearts received across all posts (from statsV2). Present on profile rows.",
      "title": "Heart Count",
      "type": "integer"
    },
    "images": {
      "description": "Images for slideshow posts (postType='slideshow'). Present on post rows when applicable.",
      "items": {
        "properties": {
          "height": {
            "title": "Height",
            "type": "integer"
          },
          "ordinal": {
            "title": "Index",
            "type": "integer"
          },
          "urlList": {
            "title": "Image URLs",
            "type": "array"
          },
          "width": {
            "title": "Width",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "title": "Slideshow Images",
      "type": "array"
    },
    "isAd": {
      "description": "Whether this post is a paid advertisement. Present on post rows.",
      "title": "Is Ad",
      "type": "boolean"
    },
    "isAigc": {
      "description": "Whether TikTok labels this as AI-generated content. Present on post rows.",
      "title": "Is AI Generated Content",
      "type": "boolean"
    },
    "isECVideo": {
      "description": "Whether this is a TikTok Shop / e-commerce video. Present on post rows.",
      "title": "Is E-Commerce Video",
      "type": "boolean"
    },
    "isLive": {
      "description": "True when TikTok reports the account as currently streaming. Present on profile rows when live status is resolved (omitted for accounts TikTok does not report).",
      "title": "Live now",
      "type": "boolean"
    },
    "isOrganization": {
      "description": "Whether the account is registered as an organization. Present on profile rows.",
      "title": "Is Organization",
      "type": "boolean"
    },
    "isPinned": {
      "description": "True when the account pinned this video to the top of its profile. Only emitted for pinned videos.",
      "title": "Pinned",
      "type": "boolean"
    },
    "item_control": {
      "description": "TikTok content-control flags (e.g. duet/stitch/download restrictions at the raw API level). Present on post rows when available.",
      "title": "Item Control",
      "type": "object"
    },
    "language": {
      "description": "Account's primary language setting. Present on profile rows when available.",
      "title": "Language",
      "type": "string"
    },
    "likeCount": {
      "description": "Number of likes/diggs. Present on post rows.",
      "title": "Like Count",
      "type": "integer"
    },
    "liveRoomId": {
      "description": "TikTok live room identifier while the account is streaming. Present on profile rows when live.",
      "title": "Live room ID",
      "type": "string"
    },
    "liveRoomTitle": {
      "description": "Title of the current live stream. Present on profile rows while the account is live.",
      "title": "Live title",
      "type": "string"
    },
    "liveStartTime": {
      "description": "Unix timestamp (seconds) when the current live stream started.",
      "title": "Live start time",
      "type": "integer"
    },
    "liveViewerCount": {
      "description": "Number of viewers in the current live stream, when TikTok reports it.",
      "title": "Live viewers",
      "type": "integer"
    },
    "locationCreated": {
      "description": "ISO country code where the post was created. Present on post rows when available.",
      "title": "Location Created",
      "type": "string"
    },
    "mediaUrlExpiresAt": {
      "description": "ISO 8601 UTC datetime when signed media URLs (video/cover) expire. Present on post rows when signed URLs are present.",
      "title": "Media URL Expires At",
      "type": "string"
    },
    "medianPlays": {
      "description": "Median play count over the videos fetched for this account in this run (enabled by computedStats).",
      "title": "Median plays",
      "type": "number"
    },
    "mentions": {
      "description": "@mentions in the post caption. Present on post rows when present.",
      "items": {
        "properties": {
          "awemeId": {
            "title": "Mentioned Post ID",
            "type": "string"
          },
          "end": {
            "title": "End Offset",
            "type": "integer"
          },
          "start": {
            "title": "Start Offset",
            "type": "integer"
          },
          "username": {
            "title": "Username",
            "type": "string"
          }
        },
        "type": "object"
      },
      "title": "Mentions",
      "type": "array"
    },
    "mixId": {
      "description": "TikTok mix identifier used for paginating playlist videos. Present on playlist rows.",
      "title": "Mix ID",
      "type": "string"
    },
    "music": {
      "description": "Sound/music used in the post. Present on post rows. Note: playUrl is a signed CDN URL bound to the IP/session that fetched it and may return HTTP 403 if opened from a different network (same behavior as video.playUrl/downloadAddr).",
      "properties": {
        "album": {
          "title": "Album",
          "type": "string"
        },
        "authorName": {
          "title": "Author",
          "type": "string"
        },
        "coverUrl": {
          "title": "Cover URL",
          "type": "string"
        },
        "dspLinks": {
          "description": "Links to the sound on external music platforms (Spotify, Apple Music, etc.) when TikTok provides them.",
          "title": "DSP Links",
          "type": "array"
        },
        "duration": {
          "title": "Duration (s)",
          "type": "integer"
        },
        "id": {
          "title": "Music ID",
          "type": "string"
        },
        "isCommerceMusic": {
          "title": "Is Commerce Music",
          "type": "boolean"
        },
        "isCopyrighted": {
          "title": "Is Copyrighted",
          "type": "boolean"
        },
        "isPrivate": {
          "title": "Is Private Sound",
          "type": "boolean"
        },
        "isUnlimitedMusic": {
          "title": "Is Unlimited Music",
          "type": "boolean"
        },
        "musicUrl": {
          "title": "Music URL",
          "type": "string"
        },
        "original": {
          "title": "Original Sound",
          "type": "boolean"
        },
        "playUrl": {
          "title": "Play URL",
          "type": "string"
        },
        "shootDuration": {
          "title": "Shoot Duration (s)",
          "type": "integer"
        },
        "title": {
          "title": "Title",
          "type": "string"
        }
      },
      "title": "Music",
      "type": "object"
    },
    "name": {
      "description": "Playlist display name. Present on playlist rows.",
      "title": "Playlist name",
      "type": "string"
    },
    "openFavorite": {
      "description": "Whether the user's liked videos are publicly visible. Present on profile rows.",
      "title": "Open Favorite",
      "type": "boolean"
    },
    "originalItem": {
      "description": "Whether TikTok flags this post as original (non-duplicated) content. Present on post rows.",
      "title": "Original Item",
      "type": "boolean"
    },
    "playCount": {
      "description": "Number of video plays. Present on post rows.",
      "title": "Play Count",
      "type": "integer"
    },
    "playlistId": {
      "description": "TikTok playlist identifier. Present on playlist rows.",
      "title": "Playlist ID",
      "type": "string"
    },
    "playlistUrl": {
      "description": "Canonical TikTok URL of the playlist.",
      "title": "Playlist URL",
      "type": "string"
    },
    "poi": {
      "description": "Tagged location/point-of-interest details (name, address, city) attached to the post. Present on post rows when the creator tagged a location.",
      "title": "Point of Interest",
      "type": "object"
    },
    "postId": {
      "description": "TikTok's unique post/video ID (string to preserve 64-bit precision). Present on post rows.",
      "title": "Post ID",
      "type": "string"
    },
    "postType": {
      "description": "Either 'video' or 'slideshow'. Present on post rows.",
      "title": "Post Type",
      "type": "string"
    },
    "postUrl": {
      "description": "Direct URL to the TikTok post. Present on post rows.",
      "title": "Post URL",
      "type": "string"
    },
    "postsPerWeek": {
      "description": "Posting frequency implied by the createTime span of the fetched videos (enabled by computedStats).",
      "title": "Posts per week",
      "type": "number"
    },
    "privateAccount": {
      "description": "Whether the account is set to private. Present on profile rows.",
      "title": "Private Account",
      "type": "boolean"
    },
    "privateItem": {
      "description": "Whether the post is set to private. Present on post rows.",
      "title": "Private Item",
      "type": "boolean"
    },
    "profileEmbedPermission": {
      "description": "Whether the user allows profile embedding. Present on profile rows.",
      "title": "Profile Embed Permission",
      "type": "integer"
    },
    "profileTab": {
      "description": "Visibility settings for profile tabs (music, questions, playlists). Present on profile rows.",
      "properties": {
        "showMusicTab": {
          "type": "boolean"
        },
        "showPlayListTab": {
          "type": "boolean"
        },
        "showQuestionTab": {
          "type": "boolean"
        }
      },
      "title": "Profile Tab",
      "type": "object"
    },
    "profileUrl": {
      "description": "Direct TikTok profile URL (https://www.tiktok.com/@username). Present on profile rows.",
      "title": "Profile URL",
      "type": "string"
    },
    "profileUsername": {
      "description": "Username of the profile that was scraped — links post rows back to their source profile. Present on post rows.",
      "title": "Profile Username",
      "type": "string"
    },
    "repostCount": {
      "description": "Number of reposts. Present on post rows when available.",
      "title": "Repost Count",
      "type": "integer"
    },
    "roomId": {
      "description": "Live room ID — non-empty when the user is currently streaming. Present on profile rows when live.",
      "title": "Room ID",
      "type": "string"
    },
    "rowType": {
      "description": "Discriminator field: 'profile' for profile rows, 'video' for video post rows, 'repost' for reposted post rows, 'playlist' for playlist metadata rows",
      "title": "Row Type",
      "type": "string"
    },
    "scrapedAt": {
      "description": "ISO 8601 UTC datetime when the profile was scraped. Present on profile rows.",
      "title": "Scraped At",
      "type": "string"
    },
    "secUid": {
      "description": "TikTok secure user identifier used in API calls. Present on profile rows.",
      "title": "Secure UID",
      "type": "string"
    },
    "shareCount": {
      "description": "Number of shares. Present on post rows.",
      "title": "Share Count",
      "type": "integer"
    },
    "shareEnabled": {
      "description": "Whether sharing is enabled for this post. Present on post rows.",
      "title": "Share Enabled",
      "type": "boolean"
    },
    "sourcePlaylistId": {
      "description": "Playlist the video was collected from when it was fetched via playlistUrls.",
      "title": "Source playlist ID",
      "type": "string"
    },
    "stickersOnItem": {
      "description": "Interactive stickers (polls, Q&A, etc.) overlaid on the post, with their text and position data. Present on post rows when the post has stickers.",
      "title": "Stickers On Item",
      "type": "array"
    },
    "stitchEnabled": {
      "description": "Whether stitching is allowed for this post. Present on post rows.",
      "title": "Stitch Enabled",
      "type": "boolean"
    },
    "stitchSetting": {
      "description": "Who can stitch the user's videos. Present on profile rows.",
      "title": "Stitch Setting",
      "type": "integer"
    },
    "textLanguage": {
      "description": "Detected language code of the caption text. Present on post rows when available.",
      "title": "Text Language",
      "type": "string"
    },
    "ttSeller": {
      "description": "Whether the account is a TikTok Shop seller. Present on profile rows.",
      "title": "TT Seller",
      "type": "boolean"
    },
    "userId": {
      "description": "TikTok internal user ID (string to preserve 64-bit precision). Present on profile rows.",
      "title": "User ID",
      "type": "string"
    },
    "username": {
      "description": "TikTok username (handle) without the @ prefix. Present on profile rows.",
      "title": "Username",
      "type": "string"
    },
    "verified": {
      "description": "Whether the account has TikTok's verified badge. Present on profile rows.",
      "title": "Verified",
      "type": "boolean"
    },
    "video": {
      "description": "Video technical metadata and signed play/cover URLs. Present on post rows. Note: playUrl/downloadAddr are bound to the IP/session that fetched them and may return HTTP 403 if opened from a different network.",
      "properties": {
        "bitrate": {
          "title": "Bitrate",
          "type": "integer"
        },
        "bitrateInfo": {
          "description": "Available quality/bitrate variants for this video, each with its own signed play URL.",
          "title": "Bitrate Info",
          "type": "array"
        },
        "codecType": {
          "title": "Codec",
          "type": "string"
        },
        "cover": {
          "title": "Cover Image URL",
          "type": "string"
        },
        "definition": {
          "title": "Definition",
          "type": "string"
        },
        "downloadAddr": {
          "title": "Download URL",
          "type": "string"
        },
        "duration": {
          "title": "Duration (s)",
          "type": "integer"
        },
        "dynamicCover": {
          "title": "Dynamic Cover URL",
          "type": "string"
        },
        "format": {
          "title": "Format",
          "type": "string"
        },
        "hasSubtitles": {
          "description": "Whether TikTok-generated or creator-uploaded captions/subtitles are available for this video.",
          "title": "Has Subtitles",
          "type": "boolean"
        },
        "height": {
          "title": "Height (px)",
          "type": "integer"
        },
        "originCover": {
          "title": "Original Cover URL",
          "type": "string"
        },
        "playUrl": {
          "title": "Play URL",
          "type": "string"
        },
        "ratio": {
          "title": "Aspect Ratio",
          "type": "string"
        },
        "size": {
          "title": "File Size (bytes)",
          "type": "integer"
        },
        "subtitleInfos": {
          "description": "Available caption/subtitle tracks (language, format, signed URL) when hasSubtitles is true.",
          "title": "Subtitle Info",
          "type": "array"
        },
        "videoQuality": {
          "title": "Video Quality Label",
          "type": "string"
        },
        "volumeInfo": {
          "description": "Loudness/peak audio metadata reported by TikTok for this video.",
          "title": "Volume Info",
          "type": "object"
        },
        "width": {
          "title": "Width (px)",
          "type": "integer"
        }
      },
      "title": "Video",
      "type": "object"
    },
    "videoCount": {
      "description": "Number of public videos posted (from statsV2). Present on profile rows.",
      "title": "Video Count",
      "type": "integer"
    },
    "viewerRegion": {
      "description": "ISO country code of the region the post metadata was served for. Present on post rows when available.",
      "title": "Viewer Region",
      "type": "string"
    },
    "warnInfo": {
      "description": "Content warnings TikTok attaches to the post (e.g. sensitive content notices). Present on post rows when TikTok applies a warning.",
      "title": "Warning Info",
      "type": "array"
    }
  },
  "title": "TikTok Profiles and Posts",
  "views": {
    "overview": {
      "description": "TikTok profile rows (rowType='profile') and post rows (rowType='video' or 'repost') in a single dataset.",
      "display": {
        "component": "table",
        "properties": {
          "displayName": {
            "format": "text",
            "label": "Display Name"
          },
          "followerCount": {
            "format": "number",
            "label": "Followers"
          },
          "profileUrl": {
            "format": "link",
            "label": "Profile URL"
          },
          "rowType": {
            "format": "text",
            "label": "Row Type"
          },
          "scrapedAt": {
            "format": "text",
            "label": "Scraped At"
          },
          "username": {
            "format": "text",
            "label": "Username"
          },
          "videoCount": {
            "format": "number",
            "label": "Videos"
          }
        }
      },
      "title": "Profiles Overview",
      "transformation": {
        "fields": [
          "rowType",
          "username",
          "displayName",
          "followerCount",
          "videoCount",
          "profileUrl",
          "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 Account Stats & Repost History Scraper

Look up any public TikTok account and export its stats, its public video history, the content it re-shared (reposts), its playlists and its current live status. Every account comes back as a profile row plus one row per video, repost or playlist, which makes it easy to schedule the actor and follow follower, like and posting trends over time. No TikTok account, cookies or proxy configuration are required.

What this actor does

  • Account stats — exact follower, following, hearts and video counts plus display name, bio, bio link, verification, business category, avatars and account settings.
  • Public video history — walks an account's posts newest-first, up to the limit you set, instead of stopping at a fixed handful of recent posts.
  • Reposts — the videos an account re-shared from other creators, with the original author preserved.
  • Playlists — playlist names, covers, video counts and links; add individual playlist URLs to collect the videos inside them.
  • Live status — whether the account is streaming right now, with the live room title, start time and viewer count when TikTok reports them.
  • Filters and limits — a date window, a global row cap, a per-account row cap and optional derived statistics (average plays, median plays, posts per week).
  • New-video monitoring — an onlyNewVideos mode schedules the actor as a change feed: it remembers each account's newest video between runs and emits only the videos posted since.
  • Pinned posts — pinned videos carry isPinned: true and, with pinnedFirst, are emitted before the rest of the collected posts.
  • Stable play links — every post row includes an embedUrl that plays the post in TikTok's embedded player without cookies, even after the session-bound media URLs expire.
  • Batch friendly — mix usernames and profile URLs in one run; duplicates are removed automatically.
  • Empty fields are omitted — no nulls, empty strings or placeholder values anywhere.

Output per profile row

Profile rows have rowType: "profile":

  • userId, secUid, username, displayName
  • verified, privateAccount, isOrganization, ttSeller
  • bio, bioLink, bioEmail (when a valid address is written in the bio)
  • language, commerceCategory
  • followerCount, followingCount, heartCount, videoCount, diggCount — exact counts, never rounded abbreviations
  • avatarLarger, avatarMedium, avatarThumb
  • createTime, createdAt
  • commentSetting, duetSetting, stitchSetting, downloadSetting, followingVisibility, openFavorite, profileEmbedPermission, profileTab, UserStoryStatus
  • isLive, liveRoomId, liveRoomTitle, liveStartTime, liveViewerCount — present when TikTok reports the account's live status
  • averagePlays, medianPlays, postsPerWeek — only with "Add Derived Statistics" enabled, computed over the videos fetched for that account in the run
  • profileUrl, scrapedAt

Output per video or repost row

Post rows have rowType: "video" for the account's own posts and rowType: "repost" for re-shared content, with contentKind mirroring the same value:

  • profileUsername — the account the row was collected from
  • postId, postUrl, embedUrl (permanent cookieless player link), postType (video or slideshow), caption, textLanguage, locationCreated
  • createTime, createdAt
  • playCount, likeCount, commentCount, shareCount, collectCount, repostCount
  • isPinned — present when the account pinned this video to the top of its profile
  • stitchEnabled, shareEnabled, duetEnabled, commentStatus
  • isAd, isAigc, isECVideo, privateItem, forFriend, originalItem, adLabelVersion, AIGCDescription
  • author.* — author snapshot at collection time: id, secUid, username, displayName, bio, verified, privateAccount, roomId, avatarUrl, followerCount, followingCount, heartCount, videoCount
  • music.* — sound used: id, title, authorName, original, duration, album, isCopyrighted, isCommerceMusic, isUnlimitedMusic, isPrivate, shootDuration, playUrl, coverUrl, musicUrl, dspLinks
  • video.* — technical metadata and media links: width, height, duration, ratio, definition, bitrate, codecType, format, size, videoQuality, hasSubtitles, subtitleInfos, bitrateInfo, volumeInfo, playUrl, downloadAddr, cover, originCover, dynamicCover
  • images — image list for slideshow posts
  • hashtags, mentions
  • mediaUrlExpiresAt — when the signed media links expire, when TikTok provides it
  • stickersOnItem, effectStickers, diversificationLabels, channelTags, item_control, contents, poi, warnInfo — extra post metadata, present when TikTok supplies it
  • sourcePlaylistId — for videos collected from playlist URLs

Output per playlist row

Playlist rows have rowType: "playlist":

  • profileUsername — the account that owns the playlist
  • playlistId, mixId, name, videoCount
  • coverUrl, playlistUrl, scrapedAt

Input

Field Type Default Description
usernames array – TikTok usernames with or without @
profileUrls array – Full profile URLs, usable instead of or alongside usernames
contentTypes array ["profile","videos"] Any combination of profile, videos, reposts, playlists
playlistUrls array – Playlist URLs to collect the videos inside them
maxPostsPerProfile integer 30 Max post rows per account, combined across videos and reposts (0 skips posts)
maxItems integer 0 Global cap on post rows for the whole run (0 = no cap)
includeProfileInfo boolean true Set to false to emit post rows only
oldestPostDate string – Only posts published on or after this date (YYYY-MM-DD, UTC)
newestPostDate string – Only posts published on or before this date (YYYY-MM-DD, UTC)
includeLiveStatus boolean true Adds live status fields to profile rows when TikTok reports them
computedStats boolean false Adds average plays, median plays and posts per week to profile rows
onlyNewVideos boolean false Monitoring mode: emit only videos posted since the previous run of the same account
pinnedFirst boolean false Emit pinned videos before the rest of the post rows

Example: stats snapshot for a watchlist

{
  "usernames": ["nike", "adidas", "puma"],
  "contentTypes": ["profile"],
  "maxPostsPerProfile": 0,
  "computedStats": true
}

Example: recent videos and reposts since a date

{
  "usernames": ["natgeo", "bbcnews"],
  "contentTypes": ["profile", "videos", "reposts"],
  "maxPostsPerProfile": 50,
  "oldestPostDate": "2026-09-01"
}

Example: repost history only

{
  "usernames": ["khaby.lame"],
  "contentTypes": ["reposts"],
  "maxPostsPerProfile": 100
}

Example: collect the videos inside a playlist

{
  "playlistUrls": ["https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178"],
  "maxPostsPerProfile": 100
}

Example: full history for a short list

{
  "usernames": ["corgibobaa"],
  "contentTypes": ["videos"],
  "maxPostsPerProfile": 500,
  "maxItems": 500
}

Example: new-video monitoring

{
  "usernames": ["natgeo", "bbcnews"],
  "contentTypes": ["profile", "videos"],
  "maxPostsPerProfile": 50,
  "onlyNewVideos": true
}

Schedule this input daily. The first run returns the account's videos (up to the cap) and remembers the newest one; every later run returns only videos posted since the previous run, so you get a clean new-video feed without duplicates. Reposts and playlists are not filtered by this option.

Use cases

  • Influencer vetting — pull follower counts, engagement counters and recent performance for a shortlist of creators.
  • Follower growth tracking — schedule a stats-only run to build a time series of followers, hearts and video counts.
  • Competitor monitoring — watch posting cadence and engagement for brand accounts with date-windowed runs.
  • Repost analysis — see exactly which outside content a creator chooses to amplify.
  • Playlist research — export curated playlists as structured video lists.
  • Live campaign checks — confirm whether an account is live and capture the stream details in the same run.

FAQ

Do I need a TikTok account, cookies or a proxy?

No. The actor reads public profile data exactly as any logged-out visitor could. There is nothing to configure beyond your input list. (Older versions accepted sessionCookie, cookies and ttwid; those fields were removed because they never changed what the actor returns — old saved tasks that still send them keep working unchanged.)

How does onlyNewVideos behave on the first run?

The first run for an account returns all videos it collects (up to Max Post Rows per Profile) and stores the newest video as the monitoring checkpoint. Every following run returns only videos newer than that checkpoint. If the stored state is ever lost, the next run simply behaves like a first run again — you never get an error.

Why did a monitoring run return no video rows?

Either the account posted nothing since the previous run, or the checkpoint already covers its newest video. The run still succeeds and still emits the profile row, so a scheduled stats-only watch keeps working.

How far back does the video history go?

As far as you ask it to. maxPostsPerProfile caps the rows per account, and date filters let you stop at a chosen day. Large accounts can be paged to hundreds of videos; very large request sizes simply take longer.

Why does an account show no reposts?

Many accounts genuinely never repost. When an account has no publicly visible reposts, the run still succeeds and simply emits no repost rows.

Why can reposts be missing when I ask for both videos and reposts?

maxPostsPerProfile is a combined cap and videos are written first, so a video-heavy account can use the whole budget on videos. Choose reposts only if repost history is what you need.

Why are some fields missing from a row?

Empty fields are omitted on purpose. Some TikTok accounts do not publish a bio link, a location, subtitles or hashtags, and some payloads do not carry every optional flag — those fields are left out rather than filled with blanks.

What do averagePlays and medianPlays cover?

They are computed over the videos returned for that account in the same run, not over the account's entire history. Fetch more videos for a wider window.

The video.playUrl, video.downloadAddr and music.playUrl links are short-lived addresses that TikTok binds to the session that requested them; opening them later usually returns Access Denied. They are kept because existing integrations reference them, but embedUrl is the durable, cookieless way to play a post: it is a permanent TikTok embed link that opens the post in TikTok's own player in any browser, with no account or cookies. postUrl remains the canonical link to the post page, and the image links (cover, originCover, avatars, playlist covers) resolve normally.

Which videos does pinnedFirst reorder?

TikTok lets an account pin up to three videos to the top of its profile. When pinnedFirst is on, any pinned video collected in the run is emitted before the other post rows, and it carries isPinned: true. Pinned videos normally appear inside their chronological position in TikTok's own API, so without this option they keep that position.

What happens to private, suspended or misspelled accounts?

They are skipped: no rows are written for them, the run still succeeds and the status message reports how many accounts could not be found. Profile stats for private accounts are returned when TikTok makes them public.

Is the account location or country included?

TikTok no longer includes an account region in its public profile payload, so the actor does not emit one.

Can I track changes over time?

Yes. Schedule the actor with a stats-only input and compare followerCount, heartCount and videoCount between runs using scrapedAt as the timestamp.

Is this affiliated with TikTok?

No. It is a third-party actor that reads publicly available TikTok web data.

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 tva5GT3U0Q1bbpOGj. Documentation is regenerated from the default published build; private drafts are not included.