# TikTok Search Scraper – Videos by Keyword (`sfoln/tiktok-search`)

Search TikTok videos by keyword, sorted by relevance, likes or date: caption, author, plays, likes, comments, shares, saves, duration, music and hashtags, one JSON record per video. $0.40 per 1,000 videos + $0.003 per results page. Repeated videos are never charged.

- Family: Social media data
- Categories: Social media, Videos, Automation
- Availability: on request (private on Apify). Email contact@sfoln.com with subject "Access request: TikTok Search Scraper – Videos by Keyword (sfoln/tiktok-search)" before calling; calls fail until it is public.
- JSON: https://www.sfoln.com/actors/tiktok-search.json
- MCP: https://mcp.apify.com?tools=sfoln/tiktok-search
- REST (sync): POST https://api.apify.com/v2/actors/sfoln~tiktok-search/run-sync-get-dataset-items
- REST (async): POST https://api.apify.com/v2/actors/sfoln~tiktok-search/runs

TikTok Search Scraper – Videos by Keyword searches TikTok videos by keyword and returns one normalized record per video: video ID, URL, caption, posting date, duration, plays, likes, comments, shares, saves, cover image, music, hashtags, mentions and the author's handle, ID and nickname. Sort by relevance, most liked or newest, and filter by period. It's built for trend research, influencer discovery, brand and campaign monitoring, dataset building and AI agents.

## Price per delivered record

| Event | Price | Per 1,000 | Charged for |
| --- | --- | --- | --- |
| TikTok search result (`tiktok-search-result`) | $0.0004 | $0.40 / 1,000 | Charged once per TikTok video delivered as a dataset record. Query summary records are never charged. |
| TikTok search page (`tiktok-search-query`) | $0.003 | $3 / 1,000 | Charged once per page of search results that delivered at least one new video. Covers the per-request upstream fee. Also charged for an empty page the upstream billed (when the budget covers it). |

Pay-per-event, USD, billed by Apify; no platform usage charge. Only records with status `ok` are charged. Cap a run with `maxTotalChargeUsd`. Apify free plan: up to 10 per run.

## Run

```bash
curl -X POST "https://api.apify.com/v2/actors/sfoln~tiktok-search/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords":["cooking hacks"],"maxVideosPerQuery":10}'
```

MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/tiktok-search"
    }
  }
}
```

Example prompt: Search TikTok for "cooking hacks" videos from this month and list the 20 most liked, with author, plays and hashtags.

## Input

Enter keywords. Each keyword produces one dataset record per video plus one summary record per keyword.

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `keywords` (required) | array | — | Keywords: Search terms, one per line. Duplicates are removed. Accounts on the Apify free plan can process up to 10 keywords per run. |
| `maxVideosPerQuery` | integer | `30` | Max videos per keyword: How many videos to return per keyword (1–300). Each delivered video is one charged event, plus one page event per results page. |
| `sortBy` | string | `"relevance"` | Sort: Result order. One of `"relevance"`, `"most-liked"`, `"date-posted"`. |
| `datePosted` | string | `"all-time"` | Period: Only videos posted within this period. One of `"all-time"`, `"yesterday"`, `"this-week"`, `"this-month"`, `"last-3-months"`, `"last-6-months"`. |
| `region` | string | — | Proxy country: Optional 2-letter country code (US, GB, FR…). Routes the search through that country so country-restricted videos can appear; it does not filter results by country. |
| `maxQueries` | integer | `100` | Max keywords: Safety cap on the number of keywords processed in this run. |
| `concurrency` | integer | `4` | Concurrency: How many keywords are fetched in parallel (1–8). |
| `itemTimeoutSecs` | integer | `600` | Time limit per input (seconds): Pagination for one keyword stops cleanly shortly before this limit (60–3600). Raise it for very large per-input limits. |
| `includeRaw` | boolean | `false` | Include raw upstream response: Attach the unmodified provider object to each result record. |

Example input:

```json
{
  "keywords": [
    "cooking hacks"
  ],
  "maxVideosPerQuery": 10
}
```

## Output

One record per input item with `status` (`ok` is charged; `not_found`, `error`, `skipped_*` are free) and `charged`. The run stores an `OUTPUT` summary record.

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | string | object | Input: The keyword as provided. |
| `recordType` | string | Record type: video (one per delivered video, charged) \| query (one summary per keyword, never charged) |
| `position` | integer | Position: 1-based position of the video within its input |
| `query` | string | null | Keyword |
| `sortBy` | string | Sort: Summary records only. |
| `datePosted` | string | Period: Summary records only. |
| `region` | string | null | Region: Video region (rows) or proxy region filter (summary). |
| `videoId` | string | null | Video ID |
| `url` | string | null | Video URL |
| `description` | string | null | Caption |
| `createdAt` | string | null | Created at: ISO 8601 UTC |
| `durationSecs` | number | null | Duration (s) |
| `plays` | number | null | Plays |
| `likes` | number | null | Likes |
| `comments` | number | null | Comments |
| `shares` | number | null | Shares |
| `saves` | number | null | Saves |
| `coverUrl` | string | null | Cover URL |
| `musicTitle` | string | null | Music title |
| `musicAuthor` | string | null | Music author |
| `hashtags` | array | Hashtags |
| `mentions` | array | Mentions |
| `isAd` | boolean | null | Ad |
| `authorHandle` | string | null | Author handle |
| `authorId` | string | null | Author ID |
| `authorNickname` | string | null | Author nickname |
| `rowsDelivered` | integer | Videos delivered: Summary records only. |
| `pagesFetched` | integer | Pages fetched: Summary records only. |
| `pagesCharged` | integer | Pages charged: Summary records only. |
| `reachedEnd` | boolean | Reached end: Summary records only: the upstream reported no further pages. |
| `stopReason` | string | Stop reason: Summary records only: limit \| end \| budget \| max_pages \| deadline \| empty_pages \| error |
| `status` | string | Status: ok \| not_found \| error \| skipped_invalid \| skipped_budget \| skipped_free_plan |
| `charged` | boolean | Charged |
| `chargedEvent` | string | Charged event |
| `error` | object | Error |
| `warnings` | array | Warnings |
| `source` | string | Source |
| `fetchedAt` | string | Fetched at |

Example record:

```json
{
  "input": "nursing",
  "recordType": "video",
  "position": 1,
  "query": "nursing",
  "videoId": "7268287584244124971",
  "url": "https://www.tiktok.com/@thatgreygentlemanitdxz/video/7268287584244124971",
  "description": "Tìm 'musclesandnursing'",
  "createdAt": "2023-08-17T13:48:40.000Z",
  "durationSecs": 23,
  "plays": 1282645,
  "likes": 481608,
  "comments": 187,
  "shares": 2721,
  "saves": 6978,
  "coverUrl": "https://p16-sign.tiktokcdn-us.com/tos-useast5-p-0068-tx/….jpeg",
  "musicTitle": null,
  "musicAuthor": null,
  "hashtags": [],
  "mentions": [],
  "isAd": false,
  "region": "US",
  "authorHandle": "thatgreygentlemanitdxz",
  "authorId": "7267964228375413803",
  "authorNickname": "thatgreygentlemanitdxz",
  "status": "ok",
  "charged": true,
  "chargedEvent": "tiktok-search-result",
  "source": "scrapecreators",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}
```

## Related

- [TikTok User Videos Scraper](https://www.sfoln.com/actors/tiktok-user-videos.md) (`sfoln/tiktok-user-videos`)
- [TikTok Comments Scraper](https://www.sfoln.com/actors/tiktok-video-comments.md) (`sfoln/tiktok-video-comments`)
- [TikTok Engagement Rate & Audit](https://www.sfoln.com/actors/tiktok-account-audit.md) (`sfoln/tiktok-account-audit`)
- [YouTube Search Scraper](https://www.sfoln.com/actors/youtube-search.md) (`sfoln/youtube-search`)

Publisher: SFOLN LLC, contact@sfoln.com. Catalogue: https://www.sfoln.com/catalog.json. Agent guide: https://www.sfoln.com/agents.md.
