TikTok Scraper - Videos, Profiles and Hashtags
Pricing
from $0.24 / 1,000 results
TikTok Scraper - Videos, Profiles and Hashtags
Scrape TikTok videos and profiles by handle, hashtag, keyword or link. Video rows carry plays, likes, comments, shares, saves, caption, sound and author. A profile gives its own row plus its 10 or so newest videos; hashtags and search go deeper. $0.25 per 1,000 rows.
Pricing
from $0.24 / 1,000 results
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
51
Total users
27
Monthly active users
a day ago
Last modified
Categories
Share
Scrape TikTok videos and profiles by handle, hashtag, keyword or link: every video comes back with its plays, likes, comments, shares and saves, the caption, the sound, the author and the file links, and every profile with followers, lifetime likes, bio and the verified flag. Nothing to log into.
One thing to know before you spend anything: a profile returns about a dozen rows, the profile
itself plus its ten or eleven newest videos. That is all TikTok shows a signed-out visitor, and no
value of resultsPerPage changes that. Hashtags and keyword searches page much deeper, so those
are the modes to use when you want volume.
| Input | Handles, hashtags, keywords, or TikTok profile, video and tag links |
| Output | One row per video or profile: plays, likes, comments, shares, saves, caption, hashtags, tagged accounts, sound, author, file links and the input it came from; followers, lifetime likes and bio on profiles |
| Ceiling | 2,000 rows per run, or per input with resultsPerInput; a profile gives about 12 |
| Account needed | None |
| Price | $0.25 per 1,000 rows on the free plan, down to $0.244 on Business. The free plan's $5 a month covers about 20,000 |
🔍 What TikTok Scraper does
Four ways in, and you can mix them in one run:
| You give it | You get |
|---|---|
profiles | The profile row, then its newest videos, about a dozen rows per handle |
hashtags | Videos posted under the tag, paging as deep as your limit allows |
searchQueries | The videos TikTok returns for the keyword |
startUrls | A profile link, a /video/ link for one video, or a /tag/ link |
resultsPerPage counts rows for the whole run, not per input. That matters when you list
several: once the first hashtag has used the allowance, the second returns nothing. Set
resultsPerInput and each input gets its own limit.
Rows are deduplicated inside a run, so a video that turns up under two of your hashtags is returned
and billed once. maxRunSeconds stops a slow feed and hands back what it has so far, which keeps a
search that crawls along from running up a bill.
📋 What data you get from each TikTok video and profile
| What you get | Field |
|---|---|
| Which kind of row it is | type (video or profile) |
| Video id and the link a person can open | id, webVideoUrl |
| Caption, and the hashtags in it | text, hashtags |
| Accounts tagged in the caption | mentions |
| Which of your inputs found it | sourceInput, sourceType |
| TikTok's own subtitles, when you ask for them | subtitles, subtitlesLanguage |
| When it went up, and the region TikTok files it under | createTime, region |
| Plays, likes, comments, shares, saves and downloads | playCount, diggCount, commentCount, shareCount, collectCount, downloadCount |
| Whether it is an ad | isAd |
| Length, cover image and the video file links | video.duration, video.cover, video.dynamicCover, video.playAddr, video.downloadAddr |
| The sound: id, title, artist, audio link, original or not, length | music |
| Who posted it | author.id, author.uniqueId, author.nickname, author.avatar |
| Profile handle, display name, bio, avatar and the blue tick | uniqueId, nickname, signature, avatar, verified |
| Followers, following, lifetime likes and video count | followerCount, followingCount, heartCount, videoCount |
| The profile id that survives a rename, and the profile link | secUid, url |
▶️ How to scrape TikTok videos and profiles
- Open TikTok Scraper and click Try for free.
- Fill in whichever box fits: Profiles, Hashtags, Search queries or Start URLs.
- Set Max results per run, or Results per input to give each input its own limit. Start at 50 while you look at the output.
- Click Start.
- Download the dataset as JSON, CSV or Excel, or pull it from the Apify API.
Start it with every box empty and you get one labelled sample row that is not charged. It is a placeholder, so judge the real shape from the row further down this page.
💰 How much does it cost to scrape TikTok videos and profiles?
$0.25 per 1,000 rows. Paid plans pay a little less: $0.248 on Starter, $0.246 on Scale and $0.244 on Business. A profile row costs the same as a video row. On the free plan, the $5 Apify gives you each month covers about 20,000 rows.
You pay for rows that carry data. The sample row, diagnostic rows and duplicates caught inside a
run are not charged, and resultsPerPage caps both the rows and the spend.
Leaving out pinned videos is a paid option, billed per video left out as "Pinned video left out" (see the Pricing tab). Videos the likes and date filters leave out are not charged. Subtitles cost nothing extra.
One case people miss: a private account still costs its profile row, because the profile is real data even when the videos behind it are hidden.
📥 What you give it
{"profiles": ["nasa"],"hashtags": ["spacex"],"resultsPerPage": 50,"maxRunSeconds": 90}
| Field | Default | What it is |
|---|---|---|
profiles | none | Handles, with or without @. The form opens with nasa filled in as an example, which is a starting point rather than a default. |
hashtags | none | Tags, with or without #. |
searchQueries | none | Keywords to search TikTok for. |
startUrls | none | Links pasted straight in: a profile, a /video/ link or a /tag/ link. Anything else is skipped. |
resultsPerPage | 50 | Rows for the whole run, 1 to 2,000. This is also your spend cap. Not used when resultsPerInput is set. |
resultsPerInput | none | Rows for each profile, hashtag, search and link, 1 to 2,000. Empty keeps the one limit for the run. |
maxRunSeconds | 90 | Stops the scrape at this point and returns what it has, 10 to 300. Raise it if you would rather have the rows than the time back. |
minLikes, maxLikes | none | Optional add-on, off unless you set a value: keep only videos inside this likes range. A video with no like count is left out, the same as one outside the range; a count of 0 is a real count. These filters apply to videos only: a profile's own row is always returned, and its diggCount is the number of videos that account has liked. |
postedAfter, postedBefore | none | Optional add-on, off unless you set a date: keep only videos posted on or after postedAfter and before postedBefore, as dates like 2026-10-01, counted in UTC. A video with no posting date is left out, the same as one outside the range. Anything that is not a date stops the run before it starts, with a BAD_INPUT row. Hashtag and search feeds are not sorted by date or likes, so with either add-on set an input stops after 10 pages in a row with no match. |
excludePinned | false | Paid option, profiles only: leave out the videos a creator pinned to the top of their profile. TikTok marks nothing as pinned, so they are read from the list order, and a pinned video that is also the creator's newest stays in. |
includeSubtitles | false | Add TikTok's own subtitles to each video row, as text. Hashtag and search runs take longer with it on. |
sessionCookies | none | Optional: your own session, used only for your run. You are responsible for using it within the site's terms. The field is stored encrypted. |
proxyConfiguration | off | Leave it off. It is there for people sending traffic through their own servers at high volume. |
notionConnector, notionParentId | none | Optional. Write each row into a Notion database as well as the dataset. |
📤 What you get back
A real video row from a real run. The caption ends with an emoji, so it is cut short here, and the media links are trimmed:
{"ok": true,"type": "video","id": "7358577498319342891","webVideoUrl": "https://www.tiktok.com/@.../video/7358577498319342891","text": "Got me feeling like Snow White and shii... #fyp #cats #disneyprincess","createTime": "2024-04-16T21:19:04.000Z","hashtags": ["fyp", "cats", "disneyprincess"],"region": "US","playCount": 17912733,"diggCount": 3674504,"commentCount": 12854,"shareCount": 244131,"collectCount": 282047,"downloadCount": 8092,"isAd": false,"video": { "duration": 11, "cover": "https://p16-common-sign.tiktokcdn-us.com/...", "playAddr": "https://v45.tiktokcdn-us.com/...", "downloadAddr": "https://v45.tiktokcdn-us.com/..." },"music": { "id": "7402610556690860833", "title": "kagefumi", "authorName": "-", "original": true, "duration": 36 },"author": { "id": "6806757644620350470", "uniqueId": "...", "nickname": "...", "avatar": "https://p19-common-sign.tiktokcdn-us.com/..." }}
| Field | How to read it |
|---|---|
type | Videos and profiles share one dataset, so check this before anything else. |
playCount and the other counters | Read at the moment of the run. On a profile's videos a counter that could not be read is null; on hashtag and search rows it reads 0. |
text, hashtags | Empty when the creator wrote no caption or used no tags. |
video.playAddr, video.downloadAddr, video.cover | Signed links that stop working after a short while. |
music | The sound the video uses, or null when there is none. |
mentions | The accounts tagged in the caption, each as { "uniqueId", "id" }. The caption shows a tag as the person's display name, so read the handle here. On hashtag and search rows only the id is known and uniqueId is null; on a profile's video read from the short public entry, mentions is null. |
sourceInput, sourceType | What you typed that found the row, and whether it was a profile, hashtag, search or videoUrl. A video found by two inputs comes once, under the first. |
subtitles, subtitlesLanguage | Only with includeSubtitles on: the subtitles TikTok publishes for the video as plain text, and their language, such as eng-US. Both null when TikTok has none for that video or the file could not be read. |
secUid | On profile rows. It stays the same when the creator changes their handle, so track it rather than uniqueId. |
🧾 Reading the output
Three kinds of row can land in your dataset.
| Row | How to spot it | Billed |
|---|---|---|
| A video or a profile | ok: true and a type | yes |
| The sample row | _sample: true | no |
| A diagnostic | ok: false and an errorCode | no |
Filter on ok == true and you have your data. A diagnostic never stops the run; it moves on to
the next input.
| Code | What it means |
|---|---|
NOT_FOUND | TikTok shows the handle, video or tag as gone or private. |
BAD_INPUT | A handle carried characters TikTok does not use, or an option could not be used, such as a date that is not a date. For an option, nothing is searched. |
RATE_LIMITED, SERVER_ERROR, NETWORK | That item would not answer this run. Re-running usually clears it. |
NOT_SERVED | This request was not served this run. Re-run it later. Until 12 October 2026 this code was called BLOCKED. |
TIME_LIMIT | The run neared the time limit set for it on Apify and stopped, keeping every row it had delivered. If nothing had come back by then, the run ends as failed. |
NO_RESULTS | Nothing came back at all for the whole run. |
One quirk of the Overview table: its columns are the video ones, so a profile row shows almost nothing there and a diagnostic reads as a blank line. Open the row itself or download the JSON and everything is present.
💡 What people use it for
- Keeping an eye on a set of creators. Run the handles weekly and compare the counts on their newest videos.
- Pulling the videos under a campaign hashtag, then reading the captions for how people talk about it.
- Keyword research: search a phrase and see which videos TikTok actually puts in front of people.
- A quick check on one video from a link somebody dropped in a chat.
From a hashtag to a creator shortlist, in three runs:
- Run this on a hashtag in your niche and copy the
author.uniqueIdcolumn. - Paste those handles into TikTok Profile Scraper
and sort on
followerCount. - Put the
webVideoUrlof the videos worth a closer look into TikTok Comments Scraper and read what the audience says.
🚧 What it does not do
- A profile is not an archive. About a dozen rows per handle, and no input changes that.
- No comments and no follower lists. Comments come from TikTok Comments Scraper.
- The limit is shared across your inputs unless you set
resultsPerInput. One busy hashtag can use the whole run. - Subtitles only where TikTok publishes them. Nothing is generated from the audio; no subtitles
means
null. - A private account still costs its profile row. You get the profile, then a
NOT_FOUNDrow saying the videos are private. - A profile's video can arrive with
nullcounters when only the short public entry could be read. It is still a delivered row and it is charged. - On hashtag and search rows, a counter TikTok left out reads as
0, not as missing. maxRunSecondscuts quietly. When it fires you get a partial result and no row saying so, so check the log if a count looks short.- Media links expire. They are signed and short lived.
- It is not an official TikTok tool. Dami's Studio is independent and is not affiliated with or endorsed by TikTok, or by any other company named on this page.
🧭 Which TikTok scraper do you need?
| If you want | Use |
|---|---|
| Profiles, hashtags, keyword search and single videos in one run | This one |
| Follower and like counts for a list of handles | TikTok Profile Scraper |
| Videos posted under a hashtag | TikTok Hashtag Scraper |
| Videos using one sound | TikTok Sound Scraper |
| Comments under a video | TikTok Comments Scraper |
| The hashtags ranking in a country right now | TikTok Trending Hashtags |
❓ Questions people ask
Do I need a TikTok account to scrape TikTok?
No. Everything is read signed out. The cookie field is optional.
Why did a profile only return 12 rows?
That is what TikTok publishes for a creator to a signed-out visitor, so no setting gets you the full back catalogue. Hashtag and search modes are where the depth is.
Is resultsPerPage per input or per run?
Per run, the total across every input. For a limit on each one, set resultsPerInput.
Why do the numbers differ from what I see in the app?
The app rounds big counts and the row does not. Counts also move by the minute on a video that is doing well, so compare against the time of your run. If something is missing, open the page in a private browser window: what a signed-out visitor sees there is what this actor can read.
Can I call it from code or connect it to an AI assistant?
Yes. The API tab has ready-made code for
Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect
https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/tiktok-scraper. Either way the run
happens on your Apify account at the same price.
Is scraping TikTok legal?
This reads public profiles and public videos only, never private accounts or messages. Results can still contain personal data, which GDPR and similar laws cover, so have a reason for collecting it. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Include the handles, tags or links you used and the run ID, and the log is usually enough for us to see what happened.