TikTok Hashtag, Search & Profile Scraper
Pricing
from $10.00 / 1,000 results
TikTok Hashtag, Search & Profile Scraper
Extract TikTok videos from any hashtag page without dealing with TikTok's anti-bot defenses, sign-in walls, or undocumented APIs.
Extract TikTok videos from any hashtag page, search query, or user profile without dealing with TikTok's anti-bot defenses, sign-in walls, or undocumented APIs. Paste one or more hashtag, search, or profile URLs and get back a structured dataset of videos with full metadata: captions, authors, play counts, likes, music, hashtags, and direct video URLs.
Download your data as JSON, CSV, Excel, HTML, or XML directly from the Apify console.
What you can do with the data
- Trend discovery — track which videos are gaining traction inside any hashtag, who their creators are, and how engagement (plays, likes, shares) scales over time.
- Creator research — identify rising creators inside a niche by sorting hashtag results by play count or engagement ratio.
- Music intelligence — see which tracks are driving views inside a hashtag; useful for music labels, artist managers, and ad targeting.
- Competitive monitoring — run scheduled scrapes of hashtags relevant to your brand or competitor campaigns and watch the leaderboard shift.
- Dataset building — collect labeled video data (caption, hashtags, music, stats) for ML training or content classification.
- Audience research — opt-in to
commentsPerPostto pull comment text + commenter handles alongside each video, useful for sentiment analysis, FAQ mining, or surfacing high-intent viewers in a niche.
Input
| Field | Type | Required | Description |
|---|---|---|---|
startUrls | array | yes | TikTok hashtag URLs (https://www.tiktok.com/tag/<name>), search URLs (https://www.tiktok.com/search?q=<query>), or profile URLs (https://www.tiktok.com/@<username>). Individual video URLs are rejected at startup. |
maxItems | integer | yes | Max videos to collect per URL (default: 10, range: 1–500). |
commentsPerPost | integer | no | How many top-level comments to fetch per video, embedded into the video record under comments. Default 0 (skip comments). Range: 0–500. Enabling this navigates to each video's page individually — a value of 50 across 50 videos can add several minutes to the run. |
countryCode | string | no | Exit-node country for the Apify residential proxy. One of US, DE, VN, FR, GB. Default: US. Choose a country close to where the audience is concentrated for the most relevant results. |
Example input
{"startUrls": [{ "url": "https://www.tiktok.com/tag/funny" },{ "url": "https://www.tiktok.com/search?q=cooking%20tips" },{ "url": "https://www.tiktok.com/@tranthanh123" }],"maxItems": 50,"commentsPerPost": 20,"countryCode": "US"}
Output
Each scraped video is pushed to the dataset as one record. Multiple URLs run in parallel; the sourceType, sourceHashtag, sourceQuery, sourceUsername, and sourceUrl fields let you tell records apart downstream.
Example output record
{"sourceType": "hashtag","sourceHashtag": "funny","sourceQuery": null,"sourceUsername": null,"sourceUrl": "https://www.tiktok.com/tag/funny","id": "7596344392374455570","caption": "Life With Two Cats 😂 | Part 111 #cat #catsoftiktok #funnyvideos #funnycat #funnycats","createTime": 1768661758,"url": "https://www.tiktok.com/@funnyanimalshub/video/7596344392374455570","author": {"id": "7511384928216138808","uniqueId": "funnyanimalshub","nickname": "Funny Animals hub","avatar": "https://p16-common-sign.tiktokcdn.com/...jpeg","verified": false},"stats": {"playCount": 23100000,"diggCount": 3200000,"commentCount": 4852,"shareCount": 606600,"collectCount": 197600},"video": {"duration": 65,"width": 576,"height": 1024,"cover": "https://p16-common-sign.tiktokcdn.com/...image","dynamicCover": "https://p16-common-sign.tiktokcdn.com/...image","playUrl": "https://v16-webapp-prime.tiktok.com/video/...","downloadUrl": "https://v16-webapp-prime.tiktok.com/video/..."},"music": {"id": "7596344513577388807","title": "som original","authorName": "Funny Animals hub","original": true,"playUrl": "https://v16m.tiktokcdn.com/..."},"hashtags": ["cat", "catsoftiktok", "funnyvideos", "funnycat", "funnycats"],"comments": [{"commentId": "7640259390033167112","text": "this cat is a whole mood","createTime": 1778886530,"likeCount": 12,"replyCount": 0,"user": {"id": "7298733093128307714","uniqueId": "zaii.bg","nickname": "kunn 🐍","avatar": "https://p16-common-sign.tiktokcdn.com/...jpg"}}]}
The comments array is only present when commentsPerPost > 0. When it's 0 (the default), the field is omitted.
Field reference
sourceType/sourceHashtag/sourceQuery/sourceUsername/sourceUrl— which input URL produced this record (set per item so concurrent scrapes don't get jumbled).sourceTypeis"hashtag","search", or"profile";sourceHashtagis populated only for hashtag URLs,sourceQueryonly for search URLs,sourceUsernameonly for profile URLs.id/url— TikTok video ID and canonical web URL.caption/createTime— raw caption text and Unix timestamp of upload.author— uploader's TikTok ID,@handle(uniqueId), display nickname, avatar, and verified flag.stats— play / like (diggCount) / comment / share / save (collectCount) counts at scrape time.video— duration in seconds, dimensions, static cover, animated cover, and the watermarked play URL plus the no-watermarkdownloadUrl. Note: the play/download URLs are signed and expire within a few hours — re-scrape or download immediately if you need the bytes.music— sound metadata, including whether it's an original sound and a direct play URL.hashtags— list of hashtags parsed from the caption.comments— (optional, only whencommentsPerPost > 0) top-level comments fetched by visiting each video's page. Each entry hascommentId,text,createTime,likeCount,replyCount, anduser(id,uniqueId,nickname,avatar). Reply threads are not included; only the first-level comments.
How it works
This actor uses PuppeteerCrawler (Crawlee) with a Chromium browser, the puppeteer-extra-plugin-stealth patch set, and Apify fingerprint generation to mimic a real desktop browser. Per request it:
- Loads
tiktok.comfirst as a "warm-up" — drifting the mouse, scrolling, and waiting a few seconds so that session cookies and themsTokensettle. Cold sessions hitting/tag/<name>or/searchdirectly get the well-known empty 200 soft-block. - Navigates to the target page and intercepts the relevant AJAX response —
/api/challenge/item_list/for hashtag pages,/api/search/general/full/(or/api/search/item/full/) for search pages,/api/post/item_list/for profile pages — to extract the structured video list. Search responses are unwrapped (data[].item) so the downstream output schema matches the other flows. - Scrolls to load more videos until either
maxItemsis reached or the API reports no more results. - (Optional) If
commentsPerPost > 0, navigates the same browser session to each collected video's page, intercepts/api/comment/list/, scrolls the comment panel, and embeds the captured comments into that video's record before pushing to the dataset.
Heavy resources (images, media, fonts, stylesheets) and tracking hosts (analytics endpoints, GA, Facebook, DoubleClick) are blocked at the request level to cut bandwidth and speed up the run.
Notes and limitations
- Use a residential proxy in production. TikTok soft-blocks fresh datacenter IPs and IPs with scraper history by returning HTTP 200 with an empty body. The actor will log
TikTok API non-200orFailed to parse TikTok API JSONwhen this happens — switching toRESIDENTIALproxy almost always fixes it. - Hashtag, search, and profile URLs only. Single-video URLs (
/@user/video/123…) are rejected at startup. Use a different actor for those. - Signed media URLs expire.
playUrl,downloadUrl,cover, andavatarURLs are signed by TikTok withx-expiresparameters — typically a few hours. Download or pin them immediately if needed. - Region-locked content. Some hashtags return different videos depending on proxy IP region. Set
countryCodeto pin reproducible results. commentsPerPostadds wall-clock time linearly. Each video requires its own navigation + scroll cycle (~10–30s depending on how many comments load). 50 videos × 50 comments easily adds 10+ minutes to a run. Use it sparingly, or run separate scrapes for the video list and the comments if you only need comments on a small subset.- Only top-level comments. Reply threads under each comment are not fetched.
replyCounttells you how many replies exist if you need to spot threads worth fetching by other means.
Contact
Found a bug or want a feature? Email dtrungtin@gmail.com.
For more scrapers, browse the Apify Store.