TikTok Profile & Video Stats Scraper — Account Lookup, Bio avatar

TikTok Profile & Video Stats Scraper — Account Lookup, Bio

Pricing

from $20.00 / 1,000 profile scrapeds

Go to Apify Store
TikTok Profile & Video Stats Scraper — Account Lookup, Bio

TikTok Profile & Video Stats Scraper — Account Lookup, Bio

Look up TikTok accounts and videos by handle or URL — follower count, likes, video count, bio, verification, account age, business category; per-video play, like, comment, share and save counts. Creator and user stats for influencer research. No login, no cookies. Charged only for results returned.

Pricing

from $20.00 / 1,000 profile scrapeds

Rating

0.0

(0)

Developer

Nicholas Cheng

Nicholas Cheng

Maintained by Community

Actor stats

0

Bookmarked

27

Total users

10

Monthly active users

7 days ago

Last modified

Share

TikTok Profile & Video Stats Scraper

Give it a handle, get that account's full profile as clean JSON. Give it a video link, get that video's play, like, comment, share and save counts. No login, no cookies, no session tokens, no proxy configuration, no signature reverse-engineering. Pass @nasa, duolingo, https://www.tiktok.com/@nba, or https://www.tiktok.com/@nasa/video/7676868860749827342 and get back structured records you can drop into a database or hand to an agent.

You are charged only for accounts and videos that were actually found. A banned, deleted, or mistyped handle — or a deleted, private, or mistyped video link — produces an explanatory row and costs nothing.

InputTikTok handles (@name or name), profile URLs, and/or video links or IDs
OutputOne profile row per account (identity, bio, counts, interaction settings) and one row per video (counts, caption, hashtags, music, author — and, if you tick includeSubtitles, the transcript)
Price$0.02 per profile · $0.003 per video — the same on every Apify plan
Video listsNot supported. Videos are looked up one by one from the links you pass; for an account, recentVideos adds the stats of its latest ~10 videos. See What this Actor cannot do

What you get

Profiles

{
"itemType": "profile",
"handle": "duolingo",
"url": "https://www.tiktok.com/@duolingo",
"userId": "6803362232132698118",
"secUid": "MS4wLjABAAAA…",
"nickname": "Duolingo",
"bio": "the unhinged owl",
"bioLink": "https://duolingo.com",
"avatar": "https://p16-sign-va.tiktokcdn.com/…",
"isVerified": true,
"isPrivate": false,
"createdAt": "2021-01-14T00:00:00.000Z",
"followers": 17800000,
"following": 312,
"likes": 494600000,
"videoCount": 1159,
"friendCount": 208,
"isBusinessAccount": true,
"businessCategory": "Media & Entertainment",
"commentSetting": "everyone",
"duetSetting": "everyone",
"stitchSetting": "everyone",
"downloadSetting": "everyone",
"openFavorite": true,
"isUnderAge18": false
}

Counts are real numbers, not display strings — you can sort and filter without parsing "17.8M" first. createdAt is the account creation date as a real ISO timestamp, which is one of the more useful signals for spotting a freshly-minted account behind a large follower number.

secUid is TikTok's stable internal identifier. Handles get changed; secUid does not. If you are keeping a watchlist, store that.

The interaction settings — comment, duet, stitch, download — are there because creator vetting usually needs them. Whether a creator allows duets decides whether a campaign idea is even possible, and it is not something you can infer from follower count.

Contact details from the bio

Every profile row also carries what the creator published in their bio and bio link, already split into columns: emails, phones, externalLinks, linkInBio (Linktree, Beacons, Stan and similar, with the URL) and otherSocials (Instagram, YouTube, X… handles mentioned or linked). Nothing is guessed or unlocked: if the bio says "IG @name", you get otherSocials.instagram: "name"; a phone number is only reported when the bio marks it as one (a + prefix, 📞, "tel", WhatsApp), so follower counts and years are never mistaken for phone numbers. No extra charge.

Recent video performance (optional)

Set recentVideos (1–12) and each profile row also gets the account's latest videos with their real counts, plus a summary for vetting:

  • recentVideos — each video's playCount, likeCount, commentCount, shareCount, collectCount, createdAt, durationSeconds.
  • recentStats — avgPlays, medianPlays, avgLikes, avgComments, avgShares, engagementRateByPlays ((likes + comments + shares) / plays), engagementRateByFollowers ((avg likes + avg comments) / followers), postsPerWeek, newestVideoAt, oldestVideoAt.
  • Pinned videos are kept out of the averages. TikTok lists pinned videos first, and one pinned viral clip from years ago would otherwise turn "average plays" into fiction. Such videos stay in recentVideos, marked pinned: true / inStats: false with an excludedReason.

Real output for @nasa with recentVideos: 8 (two of the eight videos shown):

{
"recentVideos": [
{"videoId": "7697300954667994381", "createdAt": "2026-10-16T16:19:26.000Z", "playCount": 110800, "likeCount": 10600, "commentCount": 268, "shareCount": 313, "collectCount": 825, "durationSeconds": 121, "pinned": false, "inStats": true},
"…",
{"videoId": "7665075736742530317", "createdAt": "2026-07-21T20:09:02.000Z", "playCount": 1600000, "likeCount": 105200, "commentCount": 3068, "shareCount": 3275, "collectCount": 7633, "durationSeconds": 25, "pinned": true, "inStats": false, "excludedReason": "pinned (listed before newer videos)"}
],
"recentStats": {
"videosAnalyzed": 7,
"excludedFromStats": 1,
"avgPlays": 525000,
"medianPlays": 347600,
"avgLikes": 52892,
"avgComments": 902,
"avgShares": 1603,
"engagementRateByPlays": 0.1055,
"engagementRateByFollowers": 0.0256,
"postsPerWeek": 2.8,
"newestVideoAt": "2026-10-16T16:19:26.000Z",
"oldestVideoAt": "2026-10-01T12:59:48.000Z"
}
}

The videos are the ones TikTok shows on the creator's public embed — usually the latest 10–12. It adds a few seconds per profile and is included in the per-profile price.

Videos

One row per video link or ID you pass. Real output from a run:

{
"itemType": "video",
"videoId": "7676868860749827342",
"requestedAs": "7676868860749827342",
"url": "https://www.tiktok.com/@nasa/video/7676868860749827342",
"description": "The Moon understood the assignment 🌕",
"createdAt": "2026-08-22T14:52:29.000Z",
"durationSeconds": 28,
"playCount": 498000,
"likeCount": 54700,
"commentCount": 913,
"shareCount": 2114,
"collectCount": 4036,
"repostCount": 0,
"hashtags": [],
"mentions": [],
"music": { "id": "7677149386731735821", "title": "original sound - NASA", "authorName": "NASA", "isOriginal": false },
"authorHandle": "nasa",
"author": {
"handle": "nasa", "userId": "7664638705177150477", "secUid": "MS4wLjABAAAA…",
"nickname": "NASA", "isVerified": true,
"followers": 1400000, "likes": 6600000, "videoCount": 35
},
"isAd": false,
"isPhotoPost": false,
"cover": "https://p19-common-sign.tiktokcdn-us.com/…",
"width": 540, "height": 960,
"duetEnabled": true, "stitchEnabled": true,
"locationCreated": "US"
}

playCount, likeCount, commentCount, shareCount, collectCount (saves) and repostCount are the numbers TikTok renders into the page for that video at the moment of the request. author carries the creator's headline counts as of the same request, so a video row is enough for "how big is this creator" without a second lookup. isAd and isPhotoPost are TikTok's own flags.

Subtitles and transcripts (optional)

Tick includeSubtitles and every video row also says what is said in the video. Real output from a run (the subtitle fields of the row; the counts above are unchanged):

{
"videoId": "7667244788046892319",
"transcriptLanguage": "eng-US",
"transcript": "My name is Jared Isaacman. I'm the administrator of NASA. I don't know anything about TikTok, but my team's got it covered, and they say that you should drop your questions in the chat.",
"subtitles": [
{
"language": "eng-US",
"type": "auto-generated",
"text": "My name is Jared Isaacman. I'm the administrator of NASA. I don't know anything about TikTok, but my team's got it covered, and they say that you should drop your questions in the chat.",
"segments": [
{ "start": 0.02, "end": 1.46, "text": "My name is Jared Isaacman." },
{ "start": 1.461, "end": 3.181, "text": "I'm the administrator of NASA." },
{ "start": 3.182, "end": 5.501, "text": "I don't know anything about TikTok," },
{ "start": 5.502, "end": 6.901, "text": "but my team's got it covered," },
{ "start": 6.902, "end": 9.681, "text": "and they say that you should drop your questions in the chat." }
]
}
],
"subtitlesNote": null
}
  • transcript is TikTok's own auto-generated caption track in the spoken language, as plain text — the "what does this video say" field most people want. transcriptLanguage is TikTok's label for it.
  • subtitles lists every caption track TikTok has for the video, each with language, type (auto-generated or machine-translated), the full text, and segments — the same text split into timed cues, { start, end, text } in seconds.
  • When TikTok has no captions for a video, transcript is null, subtitles is empty, and subtitlesNote says so. This is common: music-only clips, videos without speech and some very short clips have none. In our own check, 15 of 25 videos across eleven accounts had captions.

Subtitles are part of the video row and cost nothing extra — see Pricing.


Input

{
"handles": ["@nasa", "duolingo", "netflix"],
"startUrls": ["https://www.tiktok.com/@nba"],
"videoUrls": [
"https://www.tiktok.com/@nasa/video/7676868860749827342",
"https://vm.tiktok.com/ZMabcdefg/",
"7670634456419519758"
],
"listUrl": "https://docs.google.com/spreadsheets/d/…/edit",
"maxConcurrency": 3,
"maxItems": 0
}
OptionNotes
handles@name or name. Merged and de-duplicated with startUrls, so a messy list pasted from a spreadsheet is fine.
recentVideos0–12. Also read each account's latest videos and return their counts plus averages and engagement rate. 0 = off. See Recent video performance.
startUrlsProfile URLs; the handle is read out of the URL.
videoUrlsFull video links, /photo/ links, share links (vm.tiktok.com/…, vt.tiktok.com/…, tiktok.com/t/…, followed through their redirect), or bare numeric video IDs.
listUrlA public .csv / .txt file, or a Google Sheet shared as "Anyone with the link". See Large lists.
includeSubtitlesAlso return each video's transcript and subtitle tracks. Off by default; no extra charge. See Subtitles and transcripts.
maxConcurrencyPages fetched at the same time, 1–10 (default 3).
maxItemsHard ceiling on rows for the whole run, profiles and videos together. 0 = no limit.

You can pass accounts, videos, or both in one run. Each account becomes one profile row and each video becomes one video row. Every row carries inputOrder — the position of that target in your (de-duplicated) input, starting at 1 — so results can be matched back to your own sheet even though they arrive in parallel.

If you call the Actor through the API and leave a field out, the example values from the input form are not looked up behind your back: as soon as you pass any accounts, videos or a list, the untouched examples in the other fields are ignored and never charged.

Large lists

Thousands of accounts are a normal run, not a special case:

  • Pass the list as a file. listUrl takes a Google Sheet link (the Actor fetches its CSV export) or any public .csv / .txt. With one value per row, plain names, @handles, profile links, video links and numeric video IDs are all read; a one-word header such as handle or url is skipped. With several columns, only TikTok links and @handles are read — names, follower counts or emails in other columns are ignored, so a stray word that happens to be a valid handle is never looked up or billed.
  • Parallel, with its own brakes. Requests run in parallel (maxConcurrency). If TikTok starts throttling, the whole run pauses briefly instead of hammering, and throttled targets are not written off — they are retried slowly at the end. Only targets that still fail then get a chargedForThis: false row.
  • Picks up where it stopped. If a run is migrated by the platform or you resurrect an aborted run, everything already in the dataset is skipped: not fetched again, not charged again. The resolved target list is saved as JOBS in the run's key-value store, so an edit to the sheet mid-run does not shift the numbering.
  • Progress on the run page. The status line shows targets done, profiles, videos and not-found counts as it goes.
  • Spending cap respected. If you set a maximum cost for the run, the Actor stops when it is reached.

Pricing

$0.02 per profile and $0.003 per video, on every Apify plan — Free, Bronze, Silver, Gold, Platinum, Diamond. Check the Pricing tab: all six columns are identical. That is worth checking on any Actor you compare, including this one, because the price a listing advertises in its title is not always the price a free-plan run pays.

EventPriceWhat it covers
profile-scraped$0.02One account looked up and its full profile returned — with bio contact details, and recent video stats if you asked for them.
video-scraped$0.003One video looked up by link or ID and its counts, caption, music and author returned — plus its transcript and subtitles if you asked for them.

Two events because there are two different pages being fetched and two different things being delivered — a profile page or a video page, one request each. Neither is ever split into several billable events to look tiered; that is the kind of billing trick this Actor exists to avoid.

Being straight about the video price: Actors that pull a creator's whole video list through TikTok's signed API get thirty videos per call and can price per video lower than this. This Actor does not do that — it looks up the videos you name, one page each. If what you need is "every video from this account", buy one of those instead. If what you need is "the current numbers on these specific videos" — a campaign's posts, a shortlist of creator clips, a set of links from a brief — this is the cheaper and simpler tool.

What you are not charged for

What happens here
Accounts that do not existBanned, deleted, or mistyped handles produce one row marked chargedForThis: false. Nothing is billed.
Videos that do not existDeleted, private, or mistyped links produce one row with TikTok's own reason (e.g. item doesn't exist (TikTok status 10204)) and chargedForThis: false. Nothing is billed.
Empty or placeholder rowsIf the profile or video did not come back, no data row is written. There are no filler rows in your dataset.
The free planSame code path, same fields, same limits. No demo mode, no row cap, no nulls in place of data.

What this Actor cannot do

Being straight about this up front so you do not buy the wrong tool:

  • No full video lists. TikTok loads a creator's feed through a signed API call, which this Actor does not reproduce. recentVideos covers the latest ~10–12 videos (the ones on the creator's public embed); beyond that, videos are looked up one at a time from the links or IDs you pass.
  • No hidden contact details. Contacts come only from what the creator wrote in the bio and bio link. No email is "revealed", no link-in-bio page is crawled.
  • No hashtag pages, no Explore, no search. Those pages load 200 OK for logged-out clients and then render nothing at all. We checked; there is no data in them to extract.
  • No comments, no followers, no following lists. Same restriction.
  • No private account contents. Private accounts return their public profile shell with isPrivate: true, which is itself the answer to "is this account private". Their videos are not public and come back as not found.
  • No speech recognition of our own. Transcripts are the captions TikTok itself generated for the video. If TikTok has none, you get none — we do not download the audio and transcribe it. Language detection is TikTok's too and is occasionally wrong: in our test, one German news clip came back labelled Korean, with a machine-translated English track of the same mistake. Check transcriptLanguage before relying on it.
  • Photo posts (/photo/… links) are accepted and read from the same page data as videos, with isPhotoPost: true and imageCount set and durationSeconds null. They have been exercised less than regular videos; if one comes back wrong, open an issue with the link.

This delivers less than the largest Actor in this category, and it is priced accordingly — well under half. If you need video lists, buy that one instead; this is the right tool when what you actually need is account-level data for a list of creators, or current numbers for a list of videos, and you would rather pay a small flat rate for exactly that.


What it is good for

  • Creator vetting and influencer shortlists — follower and like counts, verification, business status, account age, and whether duets and stitches are even allowed.
  • Campaign reporting — paste the links of the posts a creator delivered and get their play, like, comment, share and save counts in one run; re-run on a schedule to watch them move.
  • Watchlists — re-run a list of handles on a schedule and diff the counts. Storing secUid means a handle change does not break the series.
  • Competitor and brand monitoring — one run covers as many accounts and videos as you pass.
  • Enriching a list you already have — handles or links in, structured records out, no per-item clicking.

How it stays working

Profile and video pages are read from the JSON that TikTok itself renders into the page for logged-out visitors. There is no login, no cookie jar, no proxy pool, and no signature emulation, which means there is nothing in the path that breaks when accounts get banned or a signing algorithm rotates.

Measured from a plain datacenter address: twelve consecutive accounts, twelve out of twelve, no throttling. Videos: twelve real videos across five creators, three consecutive rounds, 36 out of 36 with full counts; the one deliberately fake ID in the same runs came back as item doesn't exist (TikTok status 10204) every time and was not charged. Bare numeric IDs resolve without knowing the creator's handle.

Subtitles come from the same page data — TikTok lists each video's caption tracks there — and the caption files are fetched the same way, with no cookies. Measured from a datacenter address: 25 videos across eleven accounts (news, sports, education, comedy; English, German and Korean speech), three rounds: the same 15 videos had captions every round, and all 48 caption downloads returned text.


Integrating

Every run writes to a standard Apify dataset — REST API, JavaScript and Python clients, scheduled runs, webhooks, and the MCP server for agent use. Three dataset views are provided: Profiles for the headline numbers, Creator vetting for the fields a shortlist actually turns on, and Videos for per-video counts.