TikTok Search Scraper (Pay Per Result)
Pricing
$0.15 / 1,000 tiktok posts
TikTok Search Scraper (Pay Per Result)
Scrape TikTok search results by keyword — pay only per result. Views, likes, comments, shares, bookmarks, channel stats, music, subtitles, direct video URLs as JSON. Drop-in replacement for apidojo/tiktok-scraper output. No proxies or login needed. Works via API, schedules and integrations.
Pricing
$0.15 / 1,000 tiktok posts
Rating
0.0
(0)
Developer
Yevhenii Molodtsov
Maintained by CommunityActor stats
0
Bookmarked
241
Total users
179
Monthly active users
12 days ago
Last modified
Categories
Share
Search TikTok by keyword and get structured video data — engagement metrics (views, likes, comments, shares, bookmarks), channel stats, music, subtitles and direct video URLs — as clean JSON, CSV or Excel.
The deal: you pay per result, nothing per hour. A keyword typically returns ~200 videos in about 5 seconds, with zero setup — no proxies, no cookies, no login, no TikTok account. Runs that find nothing cost approximately nothing.
What data do you get?
One dataset item per video, including:
- Engagement — views, likes, comments, shares, bookmarks
- Post — title/caption, hashtags, upload timestamp (raw + ISO), permanent post URL
- Channel — id, name, username, avatar, verified flag, follower/following counts, total videos and likes
- Video — width, height, ratio, duration, direct video URL, cover and thumbnail images
- Music — song id, title, artist, album, duration, cover art
- Extras — subtitle/caption tracks with URLs, POI (location) data, collab info, the keyword that found the video
How much does it cost?
$0.15 per 1,000 videos. This Actor is priced pay-per-result: you are charged only for items actually written to the dataset — not for compute time, not for retries, not for setup.
Worked example: 5 keywords × ~200 videos each ≈ 1,000 items ≈ $0.15 total.
Runs that return zero results (or fail) produce zero billable items, so they cost approximately nothing.
Quickstart
The minimal input is a single keyword:
{ "keywords": ["ai tools"] }
A richer example:
{"keywords": ["artificial intelligence", "machine learning"],"maxItems": 1000,"sortType": "RELEVANCE","location": "US","includeSearchKeywords": true}
Input parameters
| Field | Type | Default | Description |
|---|---|---|---|
keywords | array | — (required) | Search terms, each searched independently; results are combined into one dataset |
maxItems | integer | 1000 via API; the Console form prefills 100 | Global cap on output items across all keywords |
maxItemsPerKeyword | integer | — | Optional cap per single keyword; keywords are processed sequentially against the global maxItems budget |
sortType | enum | RELEVANCE | RELEVANCE, MOST_LIKED, DATE_POSTED. Sorting is applied after fetching — TikTok ignores server-side sort parameters |
location | string | US | ISO 3166-1 alpha-2 country code. Cosmetic — TikTok keys results off the exit IP, not off this parameter. The Actor rotates EU exits, which delivers roughly 1.5–1.9x cross-market disjointness, not a per-country result set |
includeSearchKeywords | boolean | true | Adds keyword + inputSource to each item |
expansion | array | [] (off) | Opt-in harvest pools: suggest, hashtag, music — see Expansion mode |
relevanceThreshold | number | 0.3 | Music pool only: fraction of a sound's first-page captions that must match the keyword before that sound is crawled. Higher = stricter |
uniqueAuthors | boolean | false | Emit at most one item per creator (channel.id) |
maxPostsPerAuthor | integer | — | Cap on items per creator in the classic search results; the expansion pools always emit at most one item per creator regardless of this value (empty = no cap) |
proxyConfiguration | object | — (leave empty) | Not needed — proxies are built in. Advanced users may route through their own |
Proxies are built into the Actor and included in the per-result price — leave
proxyConfiguration empty. Advanced users who prefer to route traffic through their own
proxies can supply them here.
Output example
{"inputSource": "artificial intelligence","id": "7668211941134847250","title": "…","views": 116870,"likes": 3806,"comments": 43,"shares": 617,"bookmarks": 267,"hashtags": ["ai", "tech"],"channel": { "id": "…", "name": "…", "username": "…", "avatar": "…", "verified": true, "url": "…", "followers": 1606104, "following": 47, "videos": null, "likes": 0 },"collabInfo": null,"uploadedAt": 1785402000,"uploadedAtFormatted": "2026-07-30T09:00:00.000Z","video": { "width": 1080, "height": 1440, "ratio": "1080p", "duration": 36.1, "url": "https://…", "cover": "https://…", "thumbnail": "https://…" },"song": { "id": 7668211998743612000, "title": "…", "artist": "…", "album": null, "duration": 36, "cover": "https://…" },"subtitleInformation": null,"postPage": "https://www.tiktok.com/@user/video/7668211941134847250","poi": null,"keyword": "artificial intelligence"}
Note:
keywordandinputSourceintentionally carry the same value — both exist for compatibility withapidojo/tiktok-scraperpipelines.
CDN links expire:
video.url,video.coverandvideo.thumbnailare signed, short-lived TikTok CDN links — download or process them promptly after the run.postPageis the permanent link to the video.
Expansion mode
By default the Actor runs the classic keyword search. Set expansion to opt into extra
harvest pools, all seeded from the keyword's own search hits:
suggest— TikTok's own search suggestions for your keyword; each suggestion is then run through the normal search.hashtag— the hashtag feeds of the tags that appear on the keyword's search results.music— the sound feeds of the sounds used by those same results.
Creators are deduplicated run-globally across every pool, so the pools stack instead of
repeating each other — measured 85–95% disjoint. With all three on, a keyword surfaces
~10x+ more unique creators: recipe goes from 123 creators on plain search to
1,551.
Each item gains an expansion_source field — relevance (classic search), suggest,
hashtag or music — naming the pool that first surfaced that creator. The keyword and
inputSource fields still carry the original input keyword, so attribution never
drifts to the suggestion, hashtag or sound that found the video.
maxItems bounds the total across all pools, so cost stays capped exactly as before.
For creator discovery rather than post collection, set uniqueAuthors (one item per
creator, across every pool). relevanceThreshold tunes how
on-topic a sound must be before the music pool crawls it.
{"keywords": ["recipe"],"expansion": ["suggest", "hashtag", "music"],"uniqueAuthors": true,"maxItems": 2000}
Honest limits
- TikTok caps a single query string at ~200 unique results. The Actor broadens coverage with automatic additional query passes — all real keyword searches, so results stay on-topic. Expect ~200–420 items per keyword.
- Expansion stops automatically once extra queries stop returning enough new items, so you never pay for redundant fetching.
- Search is fuzzy, not exact-match. TikTok's search behaves like TikTok's search: a nonsense keyword will still return ~30 loosely related videos rather than nothing.
- Zero results are surfaced loudly. A keyword that returns nothing logs a warning. A run ends failed only when TikTok never returned a single valid response for at least one keyword — blocked or network-dead — so a failed run is the signal to retry; a run where TikTok answered but there genuinely were no results succeeds with an empty dataset.
- Run-global deduplication: the same video is never written twice within a run, even when it matches several keywords or several query passes.
Migrating from apidojo/tiktok-scraper
The output schema was built field-for-field against apidojo/tiktok-scraper dataset
items — same field names, same nesting, same types (views, likes, channel.*,
video.*, song.*, subtitleInformation, poi, keyword/inputSource, …). Point
your existing pipelines, parsers and spreadsheets at this Actor unchanged.
Integrations & API
Run it from anywhere with the Apify API. Synchronous run returning items directly:
curl -X POST "https://api.apify.com/v2/acts/xmolodtsov~tiktok-search-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"keywords": ["ai tools"], "maxItems": 200}'
Or with the JavaScript client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('xmolodtsov/tiktok-search-scraper').call({keywords: ['ai tools', 'fitness'],maxItems: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
The Actor works with all standard Apify platform features: schedules (e.g. daily keyword monitoring), webhooks (get notified when a run finishes), and dataset export to JSON, CSV, Excel, XML or RSS — plus integrations like Zapier, Make and Google Sheets.
Monitoring
Every run writes a STATISTICS record to its key-value store with throughput
(items/sec), total items, request counts and per-keyword breakdowns — handy for
dashboards and alerting on scheduled runs.
FAQ
Is scraping TikTok legal? The Actor collects only publicly available data — the same information any logged-out visitor sees on TikTok search. It never logs in, never accesses private accounts, and collects no data behind authentication. As always, ensure your use of the data complies with applicable laws and TikTok's terms in your jurisdiction.
Does it download the videos?
No — it returns direct video URLs and metadata, not video files. That is exactly why
runs finish in seconds and cost fractions of a cent: no gigabytes of video ever move
through the Actor. Download the files yourself from video.url if you need them (see
the CDN-expiry note above).
Why did I get zero results? Usually an overly narrow keyword or a transient TikTok block. Per-keyword zeroes are logged as warnings. If TikTok answered and simply had nothing to give, the run succeeds with an empty dataset; if TikTok never returned a single valid response (blocked or network), the run fails loudly so you know to retry. Try broader keywords, or simply re-run — retries are free until items are produced.
Will I hit rate limits? The Actor paces its requests politely and retries transient failures automatically. For very large keyword lists, batching them into a single run is more efficient than many small runs.