TikTok User Profile Scraper — TikTok Followers, Videos, Stats avatar

TikTok User Profile Scraper — TikTok Followers, Videos, Stats

Pricing

from $1.90 / 1,000 profiles

Go to Apify Store
TikTok User Profile Scraper — TikTok Followers, Videos, Stats

TikTok User Profile Scraper — TikTok Followers, Videos, Stats

Scrape TikTok user profiles by username, URL, user id or secUid: exact follower count, likes and video count, user id, secUid, created date, bio link, plus each profile's videos with plays and captions, followers and following lists. TikTok stats and profile data as an API. No login.

Pricing

from $1.90 / 1,000 profiles

Rating

0.0

(0)

Developer

Hyperbach

Hyperbach

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

4

Monthly active users

10 hours ago

Last modified

Share

TikTok profiles with the exact counts — 143,661 followers, not 143,700 — next to the rounded ones, plus the user id, secUid, created date, bio link, business category, verified and private flags, in one row per account. Give handles, profile or video URLs, user ids, secUids or share links. Add each profile's videos (the 10 newest, or the whole history with a COMPLETE or TRUNCATED verdict against TikTok's own count), reposts, stories, playlists, followers and following. Every row says which country read it, because TikTok shows each country different numbers. Accounts that do not exist, are private or have no videos come back as a typed row, free. Monitor accounts on a schedule and get only what changed. No login, no cookies, proxies handled for you.

Why this scraper, not the other TikTok profile actors

  • Exact counts, both numbers. TikTok's page carries the exact follower, like and video counts next to the rounded ones the app shows. The lane leader returns the rounded ones (143,700 for Notion's 143,661 on 2026-10-01) and no secUid. Each profile row here has followers (exact) and followers_shown (as the app shows it), the same for likes, following and videos, with counts_precision saying which you got.
  • The whole record in one row. User id, secUid, handle, name, bio, bio link, avatar in three sizes, verified, private, organization, business category, TikTok Shop seller, language, created date, the dates the handle and the name last changed, live and story flags, and the account's comment, duet, stitch and download settings. Ids are strings everywhere, music ids included (several rivals float-cast them).
  • Labelled by the country that read it. TikTok shows each country its own view: Notion had 331 videos for a US reader and 330 for a German one on the same minute. Every row says read_country, and readCountries gives you one labelled row per country you ask for.
  • Honest rows. An account that does not exist, is private, is hidden in the read country, or has no videos gives one typed row with profile_status and a reason, and is not charged. A run TikTok refused ends PARTIAL or FAILED and says why, never "0 rows, SUCCEEDED".
  • Whole video histories, with a verdict. Ask for more videos than the account has and the run walks its list to the end: Notion's 331 videos in 72 seconds. The profile row says COMPLETE, TRUNCATED, PARTIAL or CAPPED, with the unique videos seen against TikTok's own count. Latest, Popular or Oldest order, a date window, pinned videos left out if you want. Up to the 10 newest are read without a browser.
  • Every video field the web shows. Plays, likes, comments, shares, saves, reposts; caption, hashtags, mentions with the mentioned account's id and handle; music with string ids; duration, size, definition, covers; caption tracks and the transcript from them; the tagged place; the country it was posted from; TikTok's own content category; ad, branded-content, Spark Ads, slideshow, Shop and AI-generated flags; the author's exact counts from the same run.
  • The lists around a profile. Followers and following (each with its own exact counts), reposts, the liked tab where it is public, active stories, playlists; a playlist or collection URL gives its videos.
  • Monitoring that keeps history. With onlyChanged a profile is delivered and charged only when a count, the handle, the bio or another watched field moved since the last delivery; each row carries the previous counts, the change and the change per day, and a count history keyed by the user id, so a renamed account keeps its history (previous_handle). onlyNewVideos skips videos delivered before.
  • Engagement from the run's own rows. Engagement rate per view and per follower, average and median plays, posts per week, posting hours and weekdays, top hashtags, TikTok's content categories, and a creator score, each with its formula below, computed from the videos the same run delivered. Free.
  • Drop-in for the leader's field names. outputFormat: clockworks returns profile and video rows in the field names of clockworks/tiktok-profile-scraper (authorMeta, diggCount, webVideoUrl, ...), so a pipeline built on it reads this one unchanged, with exact counts and handle-based mention links.

Who it's for

  • Influencer marketing teams and agencies — vet creators with exact follower counts, the engagement of their recent videos, their posting rhythm, business category and verification, and track them weekly with a history of counts.
  • Brands and growth teams — follow competitors' accounts: new videos as they appear, growth per day, renames, and which videos travel.
  • Researchers and data teams — the exact record with stable ids (user id, secUid, string video and music ids), labelled by the country that read it, ready to join across runs.
  • Developers moving off another actor — the leader's field names with exact counts, typed error rows and a run summary, without a minimum charge.

Quick start

One profile, exact counts

{
"profiles": [
"notionhq"
]
}

A list of creators with their 10 newest videos

{
"profiles": [
"notionhq",
"duolingo",
"https://www.tiktok.com/@mrbeast"
],
"maxVideosPerProfile": 10
}

A whole video history, with the coverage verdict

{
"profiles": [
"notionhq"
],
"maxVideosPerProfile": 10000
}

The US and the German view of the same accounts

{
"profiles": [
"notionhq",
"duolingo"
],
"readCountries": [
"US",
"DE"
]
}

Followers and following

{
"profiles": [
"notionhq"
],
"maxFollowersPerProfile": 200,
"maxFollowingPerProfile": 200
}

A daily monitor: only what changed

{
"profiles": [
"notionhq",
"duolingo"
],
"maxVideosPerProfile": 10,
"onlyChanged": true,
"onlyNewVideos": true
}

Output

One row per profile and read country, one per video, follower or following account, and playlist (row_type says which):

fieldmeaning
row_typeprofile, video, user (a follower or following account) or playlist.
inputWhat you gave in profiles, verbatim.
profile_statusok, private (counts shown, videos not), not_found (no such account: the handle is free, or the account was banned or deleted), region_restricted (TikTok hides the account from readers in the read country), unavailable (TikTok withholds the account from every reader: not private, the handle is not free; typically suspended), invalid_input (the entry is not a TikTok account; the others in the run are still read) or failed. Only ok rows with videos are charged.
status_detailWhy a profile is not ok, in words, with TikTok's own status code; on an ok row, a read that is not quite what was asked (TikTok answered for another region than the read country).
read_countryThe country the row was read from (readCountries). TikTok shows counts and videos by the reader's country.
page_regionThe region TikTok's page says it served (webapp.app-context.region).
scraped_atWhen the row was read (UTC).
user_idTikTok's numeric user id, as a string. Stable across renames.
sec_uidTikTok's secUid, the id its own APIs take.
usernameThe handle, without @.
nicknameThe display name.
bioThe profile text.
bio_linkThe link set in the profile; null when none.
bio_link_riskTikTok's own risk score of the bio link (bioLink.risk; 0 = no risk seen); null when no link.
profile_urlhttps://www.tiktok.com/@
avatar_urlThe avatar at 1080 px (an expiring TikTok link).
avatar_medium_urlThe avatar at 720 px.
avatar_thumb_urlThe avatar at 100 px.
verifiedTikTok's verified badge.
private_accountThe account is private.
is_organizationTikTok marks the account as an organization.
business_categoryThe category of a business account ("Shopping & Retail").
commerce_userA business (commerce) account.
tt_sellerThe account sells on TikTok Shop.
languageThe account's language as TikTok records it.
created_atWhen the account (profile rows) or the video (video rows) was created (UTC).
username_modified_atWhen the handle was last changed (uniqueIdModifyTime). TikTok gives 0 to a logged-out reader for most accounts (every read in stage 4), so null does not mean never renamed.
nickname_modified_atWhen the display name was last changed (nickNameModifyTime); null when TikTok gives 0, which does not mean never.
followersFollowers, exact (TikTok's statsV2), for the read country.
followingAccounts followed, exact.
likesLikes received (hearts) on a profile, exact; likes of the video on a video row.
videosThe account's video count as TikTok shows it to the read country.
friendsMutual follows.
liked_videosVideos the account has liked.
followers_shownFollowers as the app rounds them (143,700 for 143,661).
following_shownFollowing as the app shows it.
likes_shownLikes as the app rounds them.
videos_shownVideos as the app shows them.
counts_precisionexact (TikTok's exact counts), as_shown (only the rounded ones were served), or on videos exact_plays_rounded (TikTok's web rounds plays even in its exact counts).
live_room_idThe live room id while the account is live.
is_liveThe account is live at read time.
has_storyThe account has an active story.
comment_settingeveryone, friends or nobody.
duet_settingeveryone, friends or nobody.
stitch_settingeveryone, friends or nobody.
download_settingeveryone, friends or nobody.
following_visibilitypublic, private or friends.
liked_publicThe account shows the videos it liked.
embed_allowedThe account allows its profile to be embedded.
playlists_tabThe profile shows a Playlists tab.
videos_requestedmaxVideosPerProfile for this run.
videos_deliveredThe profile's own videos this run delivered.
videos_routeembed (the 10 newest, each from its video page) or browser (the profile's video list walked in a browser).
videos_coverageCOMPLETE (everything asked, or every video TikTok lists), TRUNCATED (TikTok stopped serving before), PARTIAL (a read failed; the rest is delivered), CAPPED (maxItems or your maximum charge cut it).
videos_noteHow the walk went: unique videos seen against TikTok's count, list pages, why it stopped.
engagement_videosThe delivered posts the engagement figures are computed from (at least 3).
engagement_rateMean over the videos of (likes + comments + shares + saves) / plays, in percent.
engagement_rate_followersMean (likes + comments + shares + saves) per video / followers, in percent.
avg_playsMean plays of those videos.
median_playsMedian plays of those videos.
avg_likesMean likes of those videos.
avg_commentsMean comments of those videos.
avg_sharesMean shares of those videos.
avg_savesMean saves of those videos.
posts_per_weekThose videos divided by the weeks between the oldest and the newest of them.
creator_score0-100: 40 x reach (log10 followers / 8) + 40 x engagement (rate / 10 %) + 20 x activity (posts per week / 7), each capped at 1.
top_hashtagsThe hashtags of those videos, most used first: [{hashtag, videos}].
top_content_categoriesTikTok's own content category codes of those videos, most frequent first: [{category, videos}].
posting_hours_utcVideos per hour of the day: [{hour, videos}].
posting_weekdays_utcVideos per weekday: [{weekday, videos}].
followers_deliveredFollower rows this run delivered for the profile.
following_deliveredFollowing rows delivered.
reposts_deliveredRepost rows delivered.
liked_deliveredLiked-video rows delivered.
stories_deliveredStory rows delivered.
playlists_deliveredPlaylist rows delivered.
change_typeWith a monitoring memory: new (first delivery), changed or unchanged since the last delivery.
changed_fieldsThe watched fields that moved since the last delivery.
previous_read_atWhen the memory last delivered this account.
previous_followersFollowers at the previous delivery.
followers_changeFollowers now minus at the previous delivery.
followers_change_per_dayThat change per day since the previous delivery.
likes_changeLikes now minus at the previous delivery.
videos_changeVideos now minus at the previous delivery.
previous_handleThe handle the memory knew this user id by, when it changed.
first_read_atWhen the memory first read this account.
times_readHow many runs read this account into the memory.
count_historyThe memory's reads of this account, newest last: [{at, followers, following, likes, videos}] (up to 30).
media_filesFiles this row stored in the run's key-value store (downloadMedia): [{kind, key, url, bytes, reused}].
avatar_file_urlThe avatar in the run's key-value store: the link works as long as the store is kept (Apify's data retention for the run's default store).
run_tagrunTag, copied onto every row.
video_sourceposts, reposts, liked, story, playlist or collection.
source_routevideo_page (the video's own page), browser_list (the profile's list in a browser), open_list (TikTok's open lists) or embed (only the embed's fields: the video page failed).
playlist_idThe playlist of the video, or of the playlist row.
video_idTikTok's video id, as a string.
video_urlhttps://www.tiktok.com/@
captionThe video's caption.
text_languageThe caption's language as TikTok detects it.
playsPlays as TikTok's web shows them (TikTok rounds plays even in its exact counts).
commentsComments, exact.
sharesShares, exact.
savesSaves (favourites), exact.
repostsReposts, exact.
is_pinnedPinned to the profile (known on the browser route; null on the others).
is_adTikTok marks the video as an ad.
is_branded_contentThe creator's paid-partnership (branded content) toggle is on.
ad_authorizationThe creator authorized the video for Spark Ads.
is_slideshowA photo slideshow, not a video.
has_shop_productA TikTok Shop product is attached.
is_ai_generatedTikTok's AI-generated content label.
ai_labelTikTok's AI-generated content description.
is_private_videoThe video itself is private.
duration_sVideo length in seconds.
widthVideo width in pixels.
heightVideo height in pixels.
definition720p, 1080p, ...
video_formatThe file format (mp4).
size_bytesThe video file's size.
bitrateThe video bitrate.
cover_urlThe cover at full size (an expiring TikTok link).
cover_720_urlThe cover at 720 px (AVIF).
dynamic_cover_urlThe animated cover.
play_urlTikTok's play link (signed, expiring; it serves only the session that read the page).
download_urlTikTok's download link (signed, expiring).
media_expires_atWhen the soonest of the row's TikTok media links stops working (UTC).
caption_tracksTikTok's caption tracks: [{language, format, source (ASR = automatic, MT = machine translation), version, url, expires_at}].
transcriptThe spoken text from the caption track (includeTranscripts).
transcript_languageThe caption track's language.
music_idThe sound's id, as a string.
music_titleThe sound's title.
music_authorThe sound's author.
music_originalThe sound is the creator's own.
music_urlThe sound's audio link.
music_cover_urlThe sound's cover image (TikTok's link, expires).
music_duration_sThe sound's length.
hashtagsHashtags of the caption (full rows: names; clockworks rows: [{name}]).
mentionsAccounts mentioned in the caption (full rows: [{user_id, username, sec_uid}]; clockworks rows: [@username]).
slideshow_imagesThe images of a slideshow, in order.
anchorsLinks TikTok attaches to the video (an app, an effect, a product): [{type, kind, name}].
poi_idThe tagged place's id.
poi_nameThe tagged place's name.
poi_addressThe tagged place's address.
poi_cityThe tagged place's city.
poi_categoryThe tagged place's category.
location_createdThe country TikTok records the video was posted from (video page route).
content_categoryTikTok's own content category code (CategoryType).
content_labelsTikTok's own content labels (diversificationLabels), when given.
duet_enabledDuets are allowed on this video.
stitch_enabledStitches are allowed.
share_enabledSharing is allowed.
comments_enabledComments are open.
can_repostThe video can be reposted.
author_idThe author's user id.
author_usernameThe author's handle.
author_nicknameThe author's display name.
author_verifiedThe author's verified badge.
author_followersThe author's followers: exact, from this run's own read of the profile when the run read it.
author_followers_shownThe author's followers as the app rounds them.
author_likesThe author's likes received.
author_videosThe author's video count.
cover_file_urlThe cover (720 px) or the first slideshow image in the run's store.
video_file_urlThe video file in the run's store (downloadMedia: videos).
relationOn user rows: follower (follows of_username) or following (of_username follows them).
of_user_idThe profile whose list this row comes from.
of_usernameThat profile's handle.
playlist_nameThe playlist's name.
playlist_urlThe playlist's page.
playlist_video_countVideos in the playlist.
rowTypeclockworks shape: profile or video.
idclockworks shape: the video id.
textclockworks shape: the caption.
textLanguageclockworks shape: the caption's language.
createTimeclockworks shape: the video's creation time, unix seconds.
createTimeISOclockworks shape: the video's creation time (UTC).
isAdclockworks shape: an ad.
isPinnedclockworks shape: pinned (browser route).
isSponsoredclockworks shape: branded content or Spark Ads authorized.
isSlideshowclockworks shape: a slideshow.
playCountclockworks shape: plays.
diggCountclockworks shape: likes, exact.
commentCountclockworks shape: comments.
shareCountclockworks shape: shares.
collectCountclockworks shape: saves.
repostCountclockworks shape: reposts.
detailedMentionsclockworks shape: [{id, name, profileUrl}] — the profile URL uses the handle.
musicMetaclockworks shape: {musicId, musicName, musicAuthor, musicOriginal, playUrl, coverMediumUrl, originalCoverMediumUrl}.
videoMetaclockworks shape: {height, width, duration, coverUrl, originalCoverUrl, definition, format, subtitleLinks [{language, downloadLink, tiktokLink, source, sourceUnabbreviated, version}], aiVideoDescription, aiVideoSummary, transcriptionLink (null)}.
webVideoUrlclockworks shape: the video's URL.
mediaUrlsclockworks shape: stored video files.
authorMetaclockworks shape: the profile's 22 keys (id, secUid, name, nickName, signature, bioLink, avatar, fans, heart, video, following, friends, digg, createTime as unix seconds, ... — exact counts); on a video row the author's full record when the run read that profile.
fromProfileSectionclockworks shape: profile, videos (the profile's own), reposts, liked, story, playlist or collection.
isStoryclockworks shape: a story.
readCountryclockworks shape: the read country.
profileStatusclockworks shape: the profile status (ok, private, not_found, region_restricted, unavailable, failed).
hasTikTokShopProductclockworks shape: the video links a TikTok Shop product.
effectStickersclockworks shape: always empty (the web record has none).
commentsDatasetUrlclockworks shape: always null (comments are not read).
shortDramaSeriesInfoclockworks shape: always null.

Example record:

{
"row_type": "profile",
"input": "notionhq",
"profile_status": "ok",
"status_detail": null,
"read_country": "DE",
"page_region": "DE",
"scraped_at": "2026-10-01T15:31:38Z",
"user_id": "6907114026586719238",
"sec_uid": "MS4wLjABAAAAbLlR9hDWKZO75J9zJW_R9qPrgxTPRM6AH3uypENETAPOA-Dgn_H7OMFZdIcoDHda",
"username": "notionhq",
"nickname": "Notion",
"bio": "The AI workspace that works while you sleep.",
"bio_link": null,
"bio_link_risk": null,
"profile_url": "https://www.tiktok.com/@notionhq",
"avatar_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/d449c7f981ba8532f4178cd294ba3666~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=10399&refresh_token=f51e2e71&x-expires=1791039600&x-signature=xpOo3CralPUf4vMh9o%2FuksHdEMo%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
"avatar_medium_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/d449c7f981ba8532f4178cd294ba3666~tplv-tiktokx-cropcenter:720:720.jpeg?dr=10399&refresh_token=59513cc6&x-expires=1791039600&x-signature=5gEoNP%2BdqpiVeWkrI7DXzmbSoGM%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
"avatar_thumb_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/d449c7f981ba8532f4178cd294ba3666~tplv-tiktokx-cropcenter:100:100.jpeg?dr=10399&refresh_token=b927feac&x-expires=1791039600&x-signature=xaa7gEJXWievAMXahtbAGzq4Ceg%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
"verified": true,
"private_account": false,
"is_organization": true,
"business_category": null,
"commerce_user": false,
"tt_seller": false,
"language": "en",
"created_at": "2021-01-05T22:34:05Z",
"username_modified_at": null,
"nickname_modified_at": "2021-01-05T22:36:21Z",
"followers": 143667,
"following": 79,
"likes": 735367,
"videos": 330,
"friends": 67,
"liked_videos": 0,
"followers_shown": 143700,
"following_shown": 79,
"likes_shown": 735400,
"videos_shown": 330,
"counts_precision": "exact",
"live_room_id": null,
"is_live": false,
"has_story": false,
"comment_setting": "everyone",
"duet_setting": "everyone",
"stitch_setting": "everyone",
"download_setting": "everyone",
"following_visibility": "public",
"liked_public": false,
"embed_allowed": true,
"playlists_tab": false,
"videos_requested": 10000,
"videos_delivered": 331,
"videos_route": "browser",
"videos_coverage": "COMPLETE",
"videos_note": "browser walk (latest): 331 unique of 330 TikTok counts, 21 list pages, stopped: met, 71.2 s",
"engagement_videos": 331,
"engagement_rate": 4.159,
"engagement_rate_followers": 1.7699,
"avg_plays": 56926,
"median_plays": 14900,
"avg_likes": 2220,
"avg_comments": 23.5,
"avg_shares": 69.9,
"avg_saves": 229.5,
"posts_per_week": 1.51,
"creator_score": 47,
"top_hashtags": [
{
"hashtag": "notion",
"videos": 251
},
{
"hashtag": "notionapp",
"videos": 218
},
{
"hashtag": "notiontok",
"videos": 191
},
{
"hashtag": "productivity",
"videos": 37
},
{
"hashtag": "notionai",
"videos": 29
},
{
"hashtag": "notiontemplate",
"videos": 28
},
{
"hashtag": "blocktok",
"videos": 23
},
{
"hashtag": "backtoschool",
"videos": 18
},
{
"hashtag": "ai",
"videos": 16
},
{
"hashtag": "organization",
"videos": 11
}
],
"top_content_categories": [
{
"category": 120,
"videos": 171
},
{
"category": 118,
"videos": 49
},
{
"category": 105,
"videos": 33
},
{
"category": 110,
"videos": 22
},
{
"category": 116,
"videos": 13
}
],
"posting_hours_utc": [
{
"hour": 0,
"videos": 27
},
{
"hour": 1,
"videos": 7
},
{
"hour": 2,
"videos": 1
},
{
"hour": 3,
"videos": 1
},
{
"hour": 4,
"videos": 1
},
{
"hour": 9,
"videos": 1
},
{
"hour": 12,
"videos": 2
},
{
"hour": 13,
"videos": 2
},
{
"hour": 14,
"videos": 1
},
{
"hour": 15,
"videos": 8
},
{
"hour": 16,
"videos": 9
},
{
"hour": 17,
"videos": 32
},
{
"hour": 18,
"videos": 42
},
{
"hour": 19,
"videos": 25
},
{
"hour": 20,
"videos": 37
},
{
"hour": 21,
"videos": 35
},
{
"hour": 22,
"videos": 41
},
{
"hour": 23,
"videos": 59
}
],
"posting_weekdays_utc": [
{
"weekday": "Mon",
"videos": 56
},
{
"weekday": "Tue",
"videos": 77
},
{
"weekday": "Wed",
"videos": 75
},
{
"weekday": "Thu",
"videos": 69
},
{
"weekday": "Fri",
"videos": 49
},
{
"weekday": "Sat",
"videos": 4
},
{
"weekday": "Sun",
"videos": 1
}
],
"followers_delivered": null,
"following_delivered": null,
"reposts_delivered": null,
"liked_delivered": null,
"stories_delivered": null,
"playlists_delivered": null,
"change_type": null,
"changed_fields": null,
"previous_read_at": null,
"previous_followers": null,
"followers_change": null,
"followers_change_per_day": null,
"likes_change": null,
"videos_change": null,
"previous_handle": null,
"first_read_at": null,
"times_read": null,
"count_history": null,
"media_files": null,
"avatar_file_url": null,
"run_tag": null,
"video_source": null,
"source_route": null,
"playlist_id": null,
"video_id": null,
"video_url": null,
"caption": null,
"text_language": null,
"plays": null,
"comments": null,
"shares": null,
"saves": null,
"reposts": null,
"is_pinned": null,
"is_ad": null,
"is_branded_content": null,
"ad_authorization": null,
"is_slideshow": null,
"has_shop_product": null,
"is_ai_generated": null,
"ai_label": null,
"is_private_video": null,
"duration_s": null,
"width": null,
"height": null,
"definition": null,
"video_format": null,
"size_bytes": null,
"bitrate": null,
"cover_url": null,
"cover_720_url": null,
"dynamic_cover_url": null,
"play_url": null,
"download_url": null,
"media_expires_at": null,
"caption_tracks": null,
"transcript": null,
"transcript_language": null,
"music_id": null,
"music_title": null,
"music_author": null,
"music_original": null,
"music_url": null,
"music_cover_url": null,
"music_duration_s": null,
"hashtags": null,
"mentions": null,
"slideshow_images": null,
"anchors": null,
"poi_id": null,
"poi_name": null,
"poi_address": null,
"poi_city": null,
"poi_category": null,
"location_created": null,
"content_category": null,
"content_labels": null,
"duet_enabled": null,
"stitch_enabled": null,
"share_enabled": null,
"comments_enabled": null,
"can_repost": null,
"author_id": null,
"author_username": null,
"author_nickname": null,
"author_verified": null,
"author_followers": null,
"author_followers_shown": null,
"author_likes": null,
"author_videos": null,
"cover_file_url": null,
"video_file_url": null,
"relation": null,
"of_user_id": null,
"of_username": null,
"playlist_name": null,
"playlist_url": null,
"playlist_video_count": null,
"rowType": null,
"id": null,
"text": null,
"textLanguage": null,
"createTime": null,
"createTimeISO": null,
"isAd": null,
"isPinned": null,
"isSponsored": null,
"isSlideshow": null,
"playCount": null,
"diggCount": null,
"commentCount": null,
"shareCount": null,
"collectCount": null,
"repostCount": null,
"detailedMentions": null,
"musicMeta": null,
"videoMeta": null,
"webVideoUrl": null,
"mediaUrls": null,
"authorMeta": null,
"fromProfileSection": null,
"isStory": null,
"readCountry": null,
"profileStatus": null,
"hasTikTokShopProduct": null,
"effectStickers": null,
"commentsDatasetUrl": null,
"shortDramaSeriesInfo": null
}

Pricing

Pay only for the rows a run returns, with no start fee and no platform usage billed to you. Prices fall with your Apify plan:

eventperFreeStarterScaleBusiness
Profile (profile)1,000$2.50$2.125$1.90$1.90
Video (video)1,000$2.00$1.80$1.80$1.80
Follower or following account (user)1,000$3.00$2.55$2.10$1.50
Transcript on that video (transcript)1,000+$0.50+$0.425+$0.35+$0.25
Stored image (media_file)1,000$1.40$1.40$1.40$1.40
Stored video (media_video)one$0.15$0.15$0.15$0.15
Video list walked in a browser (video_walk)one$0.41$0.41$0.41$0.41

A profile row is $2.50 per 1,000 on the Free plan; with its 10 newest videos it costs $0.0225. More than the 10 newest videos, Popular or Oldest order, a date window past the newest ten, or excludePinned need one browser walk of the profile's list, charged once per profile ($0.41) and only when the walk delivers a video. Free: accounts that do not exist, are private, are hidden in the read country, could not be read or have no videos; playlist rows; a profile skipped by onlyChanged; a file an earlier run stored (linked, not charged again); a video without a caption track is not charged a transcript; any run that failed. maxItems is exact and never overshot. Enterprise plans have their own rates; the Actor's Pricing tab shows the price for your plan.

Usage patterns

  • Profile lookups at scale — Give thousands of handles, URLs or ids in profiles with maxVideosPerProfile: 0: one request per account, one row each, typed rows for the ones that are gone or private. maxItems caps the charged rows exactly. Ready-made: TikTok follower counts for a list of accounts.
  • Creator vetting — Add maxVideosPerProfile: 10 or more: the profile row gets the engagement figures, posting rhythm and creator score from those videos, and each video row carries the author's exact counts from the same run. Ready-made: Vet TikTok creators: engagement rate, score, transcripts.
  • Full histories and back-catalogue analysis — Set maxVideosPerProfile above the account's video count. The list is walked in a browser to its end, and videos_coverage with videos_note say whether every video TikTok counts was delivered. Use videoOrder: oldest to start from the first video, or videosNewerThan / videosOlderThan for a window. Ready-made: A TikTok account's full video history, with a verdict.
  • Monitoring on a schedule — Save a task with onlyChanged and onlyNewVideos and run it daily: unchanged profiles and old videos are not delivered or charged; changed profiles carry the change since the last delivery and the history of counts. Apify's own webhooks and integrations on the task send the result to Slack, email or a sheet. One thing to know: TikTok serves two US views of the exact counts from two data centres, up to 0.007% apart in the same minute (MrBeast: about 10,000 followers), so a change of that size on a large account can be a switch of view, not a real change; the row's change per day shows which. Ready-made: Monitor TikTok accounts daily: only what changed.
  • Audience lists — maxFollowersPerProfile and maxFollowingPerProfile return the accounts around a profile, newest first, each with its own exact counts, linked back with of_user_id. Ready-made: TikTok followers and following of an account.
  • Regional comparisons — readCountries reads each account from each country you list. The rows are labelled, so the two views never mix.

Input configuration

fieldtypedefaultwhat it does
profilesarray[]TikTok accounts, one per line, in any form: a handle (notionhq or @notionhq), a profile URL, a video or photo URL (its author is read), a numeric user id, a secUid, a share link (vm.tiktok.com/…), or a playlist or collection URL (its videos are read). Handles are case-insensitive; an account named twice is read once.
readCountriesarray["US"]The country each account is read from. TikTok shows the counts and the videos of the reader's country (Notion: 331 videos to a US reader, 330 to a German one), so every row says which country read it. Two countries give two labelled profile rows per account; videos and lists are read from the first country.
maxVideosPerProfileinteger0How many of each profile's own videos to deliver; 0 = the profile row only. Up to 10 newest are read from TikTok's embed and each video's page; more are read by walking the profile's video list in a browser, to the end if you ask for more than the account has, with a COMPLETE or TRUNCATED verdict against TikTok's own count. A browser walk (more than 10, Popular or Oldest order, a date window past the newest 10, excludePinned) is charged once per profile as a video_walk event, besides the videos.
videoOrderlatest / popular / oldest"latest"Which end of the video list to read from: TikTok's own Latest, Popular and Oldest tabs.
videosNewerThanstringOnly videos posted on or after this date: 2026-05-01, or a span back from today such as 30 days, 2 weeks, 6 months, 1 year (UTC).
videosOlderThanstringOnly videos posted before this date: 2026-06-01, or a span back from today (UTC).
excludePinnedbooleanfalseSkip the videos the account pinned to the top of its profile. Read in the browser, where TikTok marks them.
includeTranscriptsbooleanfalseThe spoken text of each video, from TikTok's own caption track (automatic or the creator's), in the video's language. A video without a caption track gets none; no AI transcription.
downloadMedianone / images / videos"none"Copy files into the run's key-value store, so the rows carry links that work as long as the store is kept (Apify's data retention for a run's default store; TikTok's own links expire within hours to days). Charged per file written.
maxRepostsPerProfileinteger0Videos the profile reposted, newest first, as video rows.
maxLikedPerProfileinteger0Videos the profile liked, where the account makes its liked tab public (most do not: the profile row's liked_public says which).
includeStoriesbooleanfalseThe profile's active stories as video rows (video_source story), when it has any.
includePlaylistsbooleanfalseOne free row per playlist of the profile (name, video count, URL). Give a playlist URL in Profiles for its videos.
maxFollowersPerProfileinteger0Accounts that follow the profile, newest follower first, each with its own exact counts.
maxFollowingPerProfileinteger0Accounts the profile follows, where the account shows them.
outputFormatfull / clockworks"full"Full gives flat rows with every field below. clockworks gives profile and video rows in the field names of the most used TikTok profile actor, so a pipeline built on it reads this one unchanged — with exact counts instead of rounded ones.
maxItemsinteger0Stop after this many charged rows (profiles, videos and users together); 0 = no limit. Free rows (accounts not found, private, empty) do not count. The run also stops inside your maximum charge and says so.
onlyChangedbooleanfalseMonitoring: deliver (and charge) a profile only when a count, the handle, the bio or another watched field changed since the last run that delivered it. Each row carries the previous counts, the change and the change per day.
onlyNewVideosbooleanfalseMonitoring: skip videos an earlier run of the same task already delivered.
stateStoreNamestringThe name of the memory that keeps each account's counts between runs (a count history on every row, keyed by the user id, so a renamed account keeps its history). Set by itself from the accounts when onlyChanged or onlyNewVideos is on.
runTagstringA label copied onto every row (run_tag), to tell runs apart in a shared dataset.
resumeFromRunIdstringThe id of an earlier run of this actor with the same input that stopped before the end: this run reads only the accounts it had not finished, and delivers nothing twice.

Errors

A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:

  • the status message starts with INPUT REJECTED;
  • the dataset holds one row, {"error": true, "code": "…", "message": "…"}, and no results;
  • the key-value store record ERROR holds the same object.

From code, check error on the first row before reading results.

A search that matches nothing is not an error: the dataset is empty and nothing is charged. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.

FAQ

Why do the counts differ between countries, and from the app?

TikTok serves each country its own view of an account; the differences are small for followers (under 0.5% on 96 accounts we read from the US and Germany) and sometimes one video for the video count. The app also rounds counts above 10,000. Every row says which country read it, and carries the exact and the rounded number.

What do COMPLETE, TRUNCATED, PARTIAL and CAPPED mean?

On a profile row with videos: COMPLETE = every video asked was delivered, or every video TikTok lists; TRUNCATED = TikTok stopped serving the list before the end (videos_note says how far it got against TikTok's count); PARTIAL = a read failed and the rest was delivered (a video page that failed leaves a row with the embed's fields only); CAPPED = maxItems or your maximum charge cut the videos.

Why are the 10 newest videos faster than more?

TikTok lists a profile's videos only to a real browser. The 10 newest are listed on TikTok's embed page and read from each video's own page without a browser; more, Popular or Oldest order, a window past the newest ten, or leaving pinned videos out need one browser page load per profile.

What is never charged?

Accounts that do not exist, are private, are hidden in the read country, could not be read or have no videos; playlist rows; the engagement figures; a file an earlier run already stored; a profile skipped by onlyChanged; and any run that failed.

Can I find accounts by keyword?

Not in this version. TikTok's account search is served only to a browser, and on Apify's servers it was not served to ours in any of seven tries (2026-10-01), so this Actor does not offer an input that would fail. Give the accounts by handle, URL, id or share link.

Can I get comments, the account's region, or emails?

No. Comments are served per video only to a browser session, so they are not part of this actor. TikTok does not show an account's region to a logged-out reader (actors that output one invent it). Contact finding is not built.

How are the engagement figures computed?

From the profile's own videos this run delivered (at least 3): engagement_rate = mean of (likes + comments + shares + saves) / plays, in percent; engagement_rate_followers = mean interactions per video / followers, in percent; posts_per_week = videos / weeks between the oldest and the newest; creator_score = 40 x min(1, log10(followers + 1) / 8) + 40 x min(1, engagement_rate / 10) + 20 x min(1, posts_per_week / 7).

Integration

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/tiktok-profile-scraper').call({"profiles": ["notionhq"]});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/tiktok-profile-scraper').call(run_input={'profiles': ['notionhq']})
items = client.dataset(run['defaultDatasetId']).list_items().items

CLI

$apify call hyperbach/tiktok-profile-scraper --input '{"profiles": ["notionhq"]}'

REST

curl -X POST "https://api.apify.com/v2/acts/hyperbach~tiktok-profile-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' -d '{"profiles": ["notionhq"]}'

Support

apify@hyperbach.com

This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.