# Douyin Search Scraper (`khadinakbar/douyin-search-scraper`) Actor

Scrape Douyin (China TikTok / 抖音) video search results by keyword. Returns videos with author, view/like/comment counts, music, hashtags. MCP/API-ready.

- **URL**: https://apify.com/khadinakbar/douyin-search-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, MCP servers, E-commerce
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 video returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Douyin Search Scraper

Scrape Douyin (China TikTok / 抖音) video search results by keyword. One keyword in, structured JSON videos out. MCP-ready, residential-proxy-backed, premium reliability.

### What it does

- Searches **douyin.com** for any keyword (Chinese, English, emoji, hashtag) and returns the public video results.
- Captures video title, author, view/like/comment/share/collect counts, music, hashtags, duration, publish date, video page URL, CDN stream URL.
- Filters by **sort** (relevance / latest / most liked), **publish time** (24h / 7d / 30d / 6mo), **video duration** (under 1m / 1-5m / over 5m).
- Built on Camoufox (anti-detect Firefox) + Apify Residential (HK/SG/TW/JP/MO rotation) — Douyin's JS challenge wall is cleared automatically.

### When to use this actor

- China-market trend research (which videos rank for `美食`, `穿搭`, your brand).
- Cross-border ecommerce: mining viral Douyin product videos.
- Agency competitor analysis on Douyin campaigns.
- AI agent / MCP workflow: keyword to ranked Douyin videos in one tool call.

**Not for:** Douyin user profile data, video comments, or video transcripts — see sibling actors in the portfolio.

### Output

One record per video. Key fields:

| Field | Type | Description |
|---|---|---|
| `awemeId` | string | Douyin video ID, globally unique |
| `title` | string | Video caption / description |
| `videoPageUrl` | url | Public Douyin video URL |
| `videoUrl` | url | Direct mp4 CDN URL (ephemeral) |
| `coverUrl` | url | Cover/thumbnail image |
| `duration` | int (ms) | Video length |
| `playCount` | int | Total plays |
| `likeCount` | int | Total likes |
| `commentCount` | int | Total comments |
| `shareCount` | int | Total shares |
| `collectCount` | int | Bookmarks / favorites |
| `publishedAt` | ISO 8601 | Publish timestamp |
| `authorNickname` | string | Creator display name |
| `authorUniqueId` | string | Creator handle |
| `authorUrl` | url | Creator profile URL |
| `authorFollowerCount` | int | Creator follower count |
| `musicTitle` | string | Background music title |
| `musicAuthor` | string | Music creator |
| `hashtags` | string\[] | Hashtags extracted from caption |
| `isOriginalSound` | bool | Original audio? |
| `searchKeyword` | string | The keyword that surfaced this video |
| `rank` | int | Position in search results (1-indexed) |
| `scrapedAt` | ISO 8601 | Extraction timestamp |

### Pricing

Pay-Per-Event:

| Event | Price |
|---|---|
| Actor start | $0.00005 (per GB RAM) |
| **Video returned** | **$0.005** |

50 videos = ~**$0.25**, 200 videos = ~**$1.00**, 1000 videos = ~**$5.00**.

Pay-Per-Usage (compute + proxy passthrough) is also enabled — Apify lets you pick at run time.

### Input

```json
{
  "searchQueries": ["美食", "穿搭"],
  "maxResults": 50,
  "sortBy": "relevance",
  "publishTime": "unlimited",
  "duration": "any"
}
```

- `searchQueries` (required) — array of keywords.
- `maxResults` — total cap across all keywords (1-1000, default 50).
- `sortBy` — `relevance` (default) / `latest` / `most_liked`.
- `publishTime` — `unlimited` (default) / `day` / `week` / `month` / `halfYear`.
- `duration` — `any` (default) / `under1min` / `1to5min` / `over5min`.
- `proxyConfiguration` — defaults to Apify Residential, country=HK. Override only if you have a China-region residential proxy.

### Usage

#### Apify API

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~douyin-search-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries":["美食"],"maxResults":20}'
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('khadinakbar/douyin-search-scraper').call({
  searchQueries: ['美食', 'iphone'],
  maxResults: 100,
  sortBy: 'most_liked',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
run = client.actor("khadinakbar/douyin-search-scraper").call(run_input={
    "searchQueries": ["美食"],
    "maxResults": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["likeCount"])
```

#### MCP (AI agent)

Tool name on the Apify MCP server: `apify--douyin-search-scraper`.

```text
search Douyin for the keyword "美食" (relevance, past 7 days, under 1 minute), max 30 results
```

The agent sees: keyword to ranked Douyin videos with structured engagement metrics. Charged per video returned.

### How it works

1. Camoufox Firefox launches on Apify Residential (HK by default).
2. Navigates `douyin.com/search/{keyword}?type=video&sort_type=...&publish_time=...&filter_duration=...`.
3. The page's own JavaScript fires signed `aweme/v1/web/search/item/` XHR requests — we intercept the JSON responses via `page.on('response')` (no client-side signing needed).
4. Scroll-paginates to trigger more XHRs until `maxResults` is reached.
5. Normalizes Douyin's nested aweme JSON to flat semantic fields.
6. If the HK proxy is blocked, automatically retries through SG, TW, JP, MO before honest-failing.

### Reliability

- Camoufox + Apify Residential is the only consistently working combination for Douyin from outside China.
- Datacenter proxies and Chrome+stealth are blocked.
- Some niche keywords return zero videos — actor exits **SUCCEEDED** with empty dataset (not an error).
- Full anti-bot block on every navigation across all 5 fallback countries -> run **FAILS** with clear reason.

### Sibling actors

- [`tiktok-trending-hashtags-scraper`](https://apify.com/khadinakbar/tiktok-trending-hashtags-scraper) — TikTok Creative Center trending hashtags
- [`tiktok-profile-scraper`](https://apify.com/khadinakbar/tiktok-profile-scraper) — TikTok creator profiles
- [`tiktok-video-comments-scraper`](https://apify.com/khadinakbar/tiktok-video-comments-scraper) — TikTok comments
- [`x-tweet-scraper`](https://apify.com/khadinakbar/x-tweet-scraper) — X/Twitter posts
- [Full portfolio](https://apify.com/khadinakbar)

### Legal

This actor scrapes only publicly accessible Douyin search results, with no login required. You are responsible for compliance with Douyin's Terms of Service and applicable data-protection law in your jurisdiction. Personal data must be processed with a lawful basis under GDPR / PIPL / equivalent regulation. Do not republish Douyin video content without rights clearance.

### FAQ

**Why Apify Residential and not a CN proxy?**
CN-region residential proxies are unreliable and expensive; HK / SG / TW Apify Residential reaches douyin.com fastest from Apify's runtime.

**Why is `videoUrl` sometimes a redirect or expires?**
Douyin CDN URLs are signed and time-limited. Re-fetch from `videoPageUrl` if you need a fresh stream URL.

**Does this work for English queries?**
Yes — Douyin returns mixed-language results. English brand names and product terms work; Chinese keywords return the most volume.

**Why might a keyword return fewer videos than I asked for?**
Douyin caps each search at a few hundred results. Niche keywords may return only a few dozen.

# Actor input Schema

## `searchQueries` (type: `array`):

Free-text Douyin video searches (Chinese, English, emoji, hashtag — e.g. '美食', 'iphone unboxing', '#健身'). Each keyword runs as a separate search and is paginated up to maxResults. Defaults to \['美食']. NOT a Douyin user URL — this actor only scrapes the video search results page.

## `maxResults` (type: `integer`):

Hard cap on total videos scraped and billed across all keywords. The run stops once this is reached. Defaults to 50; max 1000. Primary cost control — at $0.005/video, 50 videos is about $0.25.

## `sortBy` (type: `string`):

Douyin search sort order. 'relevance' (default) returns Douyin's default ranked feed; 'latest' filters to most recently published; 'most\_liked' surfaces highest-engagement videos. Maps to Douyin's sort\_type query parameter (0/1/2).

## `publishTime` (type: `string`):

Filter by video publish recency. 'unlimited' (default) returns videos from any date; 'day'/'week'/'month'/'halfYear' restricts to the most recent N days. Maps to Douyin's publish\_time query parameter (0/1/7/30/180).

## `duration` (type: `string`):

Filter by video length. 'any' (default) returns all durations; 'under1min' = videos shorter than 60s; '1to5min' = 60-300s; 'over5min' = videos longer than 5 minutes. Maps to Douyin's filter\_duration parameter (0/0-1/1-5/5-10000).

## `proxyConfiguration` (type: `object`):

Proxy used for all requests. Douyin blocks non-China-region datacenter IPs hard, so by default this actor uses Apify Residential automatically pinned to HK/SG/TW for highest success rate. Override only if you have a custom residential or China-region proxy; non-residential proxies will be blocked.

## Actor input object example

```json
{
  "searchQueries": [
    "美食",
    "穿搭"
  ],
  "maxResults": 50,
  "sortBy": "relevance",
  "publishTime": "unlimited",
  "duration": "any",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "HK"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

All scraped Douyin videos (one record per video).

## `summary` (type: `string`):

End-of-run summary stored at OUTPUT.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "美食"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/douyin-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["美食"],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/douyin-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "美食"
  ],
  "maxResults": 50
}' |
apify call khadinakbar/douyin-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/douyin-search-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/O6NPs36NbNmHWyAXa/builds/wGg5TlLgyTNecc2ui/openapi.json
