# Douyin 抖音 Search Scraper - Keyword + Filters & 60+ Fields (`zen-studio/douyin-search-scraper`) Actor

Extract Douyin (抖音) search results by keyword. One row per video with full creator profile, music, hashtags, video tags, and engagement stats. Filter by sort, publish window, and duration. 60+ fields per video, 46 per creator. Free tier - 10 runs.

- **URL**: https://apify.com/zen-studio/douyin-search-scraper.md
- **Developed by:** [Zen Studio](https://apify.com/zen-studio) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 15 total users, 4 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 search results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 (抖音) — Keyword Search, Filters & Full Video Metadata (2026)

<blockquote style="border-left:4px solid #4C945E;background:#F0FDF4;padding:12px 16px">
<span style="font-size:16px;font-weight:700;color:#1C1917">Search Douyin (抖音) by keyword — full video metadata, creator profile, music, hashtags, and engagement in clean structured JSON</span> <span style="font-size:15px;color:#57534E"> — sort by relevance / most-liked / newest, filter by publish window and duration.</span>
</blockquote>

![Douyin Search Scraper](https://iili.io/Bb2i43B.png)

#### Copy to your AI assistant

````

zen-studio/douyin-search-scraper on Apify. Scrapes Douyin search results by keyword with sort/publish/duration filters and optional MP4/cover/slideshow downloads. One row per video with 62 top-level fields + 42-field authorMeta, plus musicMeta, videoMeta, statistics, hashtags, server-classified videoTags. Call ApifyClient("TOKEN").actor("zen-studio/douyin-search-scraper").call(run\_input={...}), then client.dataset(run\["defaultDatasetId"]).list\_items().items. Required: keywords (string\[]). Optional: maxResultsPerQuery, sort (general/most\_liked/latest), publishTime (unlimited/one\_day/one\_week/half\_year), duration (unlimited/under\_1m/one\_to\_five/over\_5m), shouldDownloadVideos (bool, paid +$0.99/1k), shouldDownloadCovers (bool, free), shouldDownloadSlideshowImages (bool, free), videoKvStoreName (string). Full spec: GET https://api.apify.com/v2/acts/zen-studio~douyin-search-scraper/builds/default (Bearer TOKEN) → inputSchema, actorDefinition.storages.dataset, readme. Token: https://console.apify.com/account/integrations

````

<table>
<tr>
<td colspan="4" style="padding:10px 14px;background:#4C945E;border:none;border-radius:4px 4px 0 0">
<span style="color:#FAFAF9;font-size:14px;font-weight:700;letter-spacing:0.5px">Zen Studio · 抖音 + 西瓜视频 (Xigua)</span>
<span style="color:#E8F5E9;font-size:13px">&nbsp;&nbsp;&bull;&nbsp;&nbsp;Full-stack China short-video data: search, profiles, posts, transcripts</span>
</td>
</tr>
<tr>
<td style="padding:10px 14px;border:1px solid #E7E5E4;border-radius:0 0 0 4px;background:#E8F5E9;border-right:none;border-top:none;vertical-align:top;width:25%">
<a href="https://apify.com/zen-studio/douyin-search-scraper" style="color:#4C945E;text-decoration:none;font-weight:700;font-size:14px">Search</a><br>
<span style="color:#4C945E;font-size:12px;font-weight:600">&#10148; You are here</span>
</td>
<td style="padding:10px 14px;border:1px solid #E7E5E4;border-right:none;border-top:none;vertical-align:top;width:25%">
<a href="https://apify.com/zen-studio/douyin-profile-scraper" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:14px">Profiles</a><br>
<span style="color:#78716C;font-size:12px">博主 followers, posts, hashtags</span>
</td>
<td style="padding:10px 14px;border:1px solid #E7E5E4;border-right:none;border-top:none;vertical-align:top;width:25%">
<a href="https://apify.com/zen-studio/douyin-video-scraper" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:14px">Video</a><br>
<span style="color:#78716C;font-size:12px">Metadata + MP4 download</span>
</td>
<td style="padding:10px 14px;border:1px solid #E7E5E4;border-radius:0 0 4px 0;border-top:none;vertical-align:top;width:25%">
<a href="https://apify.com/zen-studio/douyin-transcripts-scraper" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:14px">Transcripts</a><br>
<span style="color:#78716C;font-size:12px">字幕 + 50-lang translation</span>
</td>
</tr>
</table>

### How to Search Douyin by Keyword

#### Basic — one keyword, default 100 results

```json
{
  "keywords": ["美食"],
  "maxResultsPerQuery": 100
}
````

#### Most-liked food videos from the last week

```json
{
  "keywords": ["美食", "家常菜"],
  "maxResultsPerQuery": 200,
  "sort": "most_liked",
  "publishTime": "one_week"
}
```

#### Newest short-form clips across multiple brand keywords

```json
{
  "keywords": ["iphone", "huawei", "xiaomi"],
  "maxResultsPerQuery": 300,
  "sort": "latest",
  "duration": "under_1m"
}
```

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `keywords` | string\[] | *required* | Search keywords. Chinese, English, hashtags, brand names, and emoji all work. |
| `maxResultsPerQuery` | integer | `100` | How many results to fetch per keyword (1–1000). Cost scales linearly. |
| `sort` | string | `general` | `general` / `most_liked` / `latest`. Relevance, most-liked first, or newest first. |
| `publishTime` | string | `unlimited` | `unlimited` / `one_day` / `one_week` / `half_year`. Restrict results to videos published in this window. |
| `duration` | string | `unlimited` | `unlimited` / `under_1m` / `one_to_five` / `over_5m`. Restrict by video length. |
| `shouldDownloadVideos` | boolean | `false` | Save MP4 video files to your key-value store. Adds **$0.99 per 1,000 successful downloads**. Image-text posts have no MP4. |
| `shouldDownloadCovers` | boolean | `false` | Save each result's cover image (JPEG) to your key-value store. Free. |
| `shouldDownloadSlideshowImages` | boolean | `false` | For image-text posts, save every slide image to your key-value store. Free. |
| `videoKvStoreName` | string | `""` | Save downloads to a named, persistent KV store you can reuse across runs (lowercase letters, digits, dashes only). Leave empty for the run's default store. |

#### Accepted keyword formats

Any string Douyin's search box accepts:

| Format | Example |
|---|---|
| Chinese word or phrase | `美食`, `家常菜`, `懒人快手菜` |
| English word | `iphone`, `huawei`, `xiaomi` |
| Hashtag | `#美食`, `#英语学习打卡` |
| Brand or person name | `Tesla`, `周杰伦` |
| Emoji | `🍜`, `🎬` |

Each keyword is searched **independently**, then results are deduped across keywords so you never pay twice for the same video. A single keyword typically returns 100–300 unique videos before Douyin stops returning new results — combine multiple keywords for broader coverage.

### What Data Can You Extract from Douyin Search?

One row per video. Each row carries **62 top-level fields**, with the full creator profile (**42 fields**) nested under `authorMeta`, plus rich sub-objects for `musicMeta` (45 fields), `videoMeta` (25 fields incl. multiple bit-rate variants), `statistics` (13 counters), `permissions` (23 flags), `commerce`, `share`, `interaction`, and arrays for `hashtags`, `videoTags` (Douyin's server-classified 3-level taxonomy), `mentions`, `chapters`, `images`.

#### Output Example

Every top-level field is shown below. Large arrays and signed CDN URLs are trimmed with `…`.

```json
{
  "id": "7610711200906065509",
  "groupId": "7610711200906065509",
  "url": "https://www.douyin.com/video/7610711200906065509",
  "shareUrl": "https://www.iesdouyin.com/share/video/7610711200906065509/?region=US&mid=…&share_sign=…",
  "type": "video",
  "awemeType": 0,
  "awemeTypeLabel": "video",
  "mediaType": 4,
  "mediaTypeLabel": "video",
  "horizontalType": 0,
  "horizontalTypeLabel": "",
  "isStory": false,
  "text": "可惜你不是湖南人，你不知道这道擂辣椒茄子炒皮蛋有多香多下饭#擂辣椒茄子皮蛋 #家常菜 #湘菜 …",
  "caption": "可惜你不是湖南人，你不知道这道擂辣椒茄子炒皮蛋有多香多下饭#擂辣椒茄子皮蛋 #家常菜 #湘菜 …",
  "itemTitle": "",
  "previewTitle": "可惜你不是湖南人，你不知道这道擂辣椒茄子炒皮蛋有多香多下饭…",
  "descLanguage": "zh",
  "createTime": 1772006790,
  "createDate": "2026-02-25",
  "region": "CN",
  "city": "Changsha",
  "cityCode": "430100",
  "isPinned": false,
  "isAd": false,
  "isPgc": false,
  "isShared": false,
  "is24Story": false,
  "is25Story": false,
  "isFirstVideo": false,
  "isLifeItem": false,
  "isKaraoke": false,
  "isDuetSing": false,
  "isFantasy": false,
  "isInScope": false,
  "isImageBeat": false,
  "isVr": false,
  "authorMeta": {
    "id": "100271680992",
    "secUid": "MS4wLjABAAAAmIUcH6QuPwoTQYnt_xVUdKH4iCdmr1jj97jzPc77_MU",
    "name": "娇娇的美食日记",
    "username": "3845294457",
    "customUsername": "dylk4dp2vnqz",
    "customUsernameUpdatedAt": 1778515670,
    "verified": true,
    "verifyType": 1,
    "customVerifyText": null,
    "verificationReason": null,
    "enterpriseVerifyReason": null,
    "signature": "💁在职妈妈的烟火日常，每日在工作与厨房间切换；\n👉用爱烹饪美食…",
    "avatarThumb": "https://p3.douyinpic.com/aweme/100x100/…",
    "avatarMedium": "https://p3.douyinpic.com/aweme/720x720/…",
    "avatar168": "https://p3.douyinpic.com/img/…~c5_168x168.jpeg",
    "avatar300": "https://p3.douyinpic.com/img/…~c5_300x300.jpeg",
    "avatarLarge": "https://p3.douyinpic.com/aweme/1080x1080/…",
    "bgImage": null,
    "shareQrCodeUri": "31953000a4734d1b75643",
    "shareUrl": null,
    "followersCount": 555931,
    "followersCountStr": null,
    "followingCount": null,
    "totalLikesReceived": null,
    "likesGivenCount": null,
    "awemeCount": null,
    "gender": "male",
    "language": "zh-Hans",
    "country": "CN",
    "ipLocation": null,
    "userAge": null,
    "birthday": null,
    "constellation": 0,
    "school": null,
    "isLiving": false,
    "roomId": null,
    "isStar": false,
    "usesSeries": false,
    "withShopEntry": true,
    "commerceUserLevel": null,
    "mcnInfo": null,
    "crossPlatform": null
  },
  "videoMeta": {
    "duration": 28375,
    "width": 2160,
    "height": 3838,
    "ratio": "540p",
    "format": "mp4",
    "isLongVideo": false,
    "isHdr": false,
    "isBytevc1": false,
    "hasWatermark": true,
    "useStaticCover": false,
    "horizontalType": null,
    "cdnUrlExpiresAt": 1778519298,
    "playUrl": "https://v5-ex-x.douyinvod.com/…",
    "downloadUrl": "https://v5-coldy.douyinvod.com/…",
    "playUrlH264": "https://v26-cold.douyinvod.com/…",
    "playUrlH265": "https://…",
    "playUrlLowBitrate": "https://…",
    "cover": "https://p11-sign.douyinpic.com/…",
    "originCover": "https://p11-sign.douyinpic.com/…",
    "dynamicCover": "https://p11-sign.douyinpic.com/…",
    "bitRates": [
      {"quality": "adapt_lowest_1080_1", "bitRate": 2936000, "fps": 30, "isH265": true, "url": "https://…"},
      {"quality": "adapt_lower_540_1", "bitRate": 3215000, "fps": 30, "isH265": false, "url": "https://…"}
    ]
  },
  "musicMeta": {
    "id": "7610711167291378459",
    "title": "@娇娇的美食日记创作的原声",
    "author": "娇娇的美食日记",
    "album": null,
    "isOriginal": true,
    "isPgc": false,
    "isCommerce": false,
    "isMatchedMetadata": false,
    "matchedPgcSound": null,
    "duration": 28,
    "startTime": 0,
    "endTime": 0,
    "ownerId": "100271680992",
    "ownerHandle": "dylk4dp2vnqz",
    "ownerNickname": "娇娇的美食日记",
    "secUid": "MS4wLjABAAAAmIUcH6QuPwoTQYnt_xVUdKH4iCdmr1jj97jzPc77_MU",
    "authorDeleted": false,
    "playUrl": "https://lf3-music-east.douyinstatic.com/obj/ies-music-hj/7610711232131418917.mp3",
    "coverThumb": "https://p3.douyinpic.com/img/…",
    "coverMedium": "https://p3.douyinpic.com/aweme/720x720/…",
    "coverLarge": "https://p3.douyinpic.com/aweme/1080x1080/…",
    "muteShare": false,
    "musicStatus": 1,
    "canBackgroundPlay": true,
    "preventDownload": false,
    "userCount": 0,
    "musicCollectCount": 0
  },
  "statistics": {
    "diggCount": 907159,
    "shareCount": 591162,
    "commentCount": 26845,
    "collectCount": 937400,
    "playCount": 0,
    "downloadCount": 0,
    "forwardCount": 0,
    "admireCount": null,
    "whatsappShareCount": 1,
    "liveWatchCount": 0,
    "exposureCount": 0,
    "loseCount": 0,
    "loseCommentCount": 0
  },
  "permissions": {
    "canDuet": true,
    "canStitch": true,
    "canDownload": false,
    "canShare": true,
    "canComment": true,
    "canRepost": true,
    "canSave": true,
    "canShowComment": true,
    "canRecord": true,
    "canReact": true,
    "canMusic": true,
    "canDouplus": true,
    "canDynamicWallpaper": false,
    "allowFriendRecommend": false,
    "isPrivate": false,
    "isProhibited": false,
    "isInReviewing": false,
    "isDeleted": false,
    "isReviewed": true,
    "withGoods": false,
    "withFusionGoods": false
  },
  "interaction": {
    "canComment": true,
    "canShowComment": true,
    "canShare": true,
    "canForward": true,
    "commentDisabled": false
  },
  "commerce": {
    "isAd": false,
    "adType": 0,
    "isLifeItem": false,
    "originalAnchorType": null,
    "withShopEntry": false,
    "withFusionShopEntry": true,
    "withCommerceEntry": false,
    "withDouEntry": false,
    "withPromotionalMusic": false,
    "commerceUserLevel": 0
  },
  "share": {
    "shareUrl": "https://www.iesdouyin.com/share/video/7610711200906065509/",
    "shareUrlSigned": "https://www.iesdouyin.com/share/video/7610711200906065509/?…&share_sign=…",
    "shareTitle": "可惜你不是湖南人，你不知道这道擂辣椒茄子炒皮蛋…",
    "shareDesc": "在抖音，记录美好生活",
    "shareLinkDesc": "5.87 复制打开抖音，看看【娇娇的美食日记的作品】…",
    "shareTemplate": null
  },
  "anchors": [],
  "hashtags": [
    {"id": "1676261542974476", "name": "擂辣椒茄子皮蛋"},
    {"id": "1601976860276750", "name": "擂辣椒皮蛋"},
    {"id": "1767587367821390", "name": "家常菜"},
    {"id": "1568858247632398", "name": "湘菜"},
    {"id": "1619283196524547", "name": "妈呀太香了"}
  ],
  "videoTags": [
    {"name": "美食", "level": 1},
    {"name": "家常菜", "level": 2},
    {"name": "下饭菜", "level": 3}
  ],
  "mentions": [],
  "chapters": [],
  "images": [],
  "series": null,
  "location": null,
  "risk": null,
  "xiguaCrossPost": null,
  "aiMetadata": null,
  "videoFile": null,
  "coverFile": null,
  "slideshowFiles": null,
  "searchKeyword": "#美食",
  "searchPosition": 1,
  "inputKeyword": "#美食",
  "inputUrl": "#美食"
}
```

### Advanced Usage

#### Hashtag tracking — pull the latest under a tag

```json
{
  "keywords": ["#美食"],
  "maxResultsPerQuery": 200,
  "sort": "latest"
}
```

Combine with a daily schedule to build a hashtag-velocity dashboard. The `createDate` and `statistics.diggCount` fields let you compute new-post rate and engagement velocity over time.

#### Competitor tracking — daily snapshot across brand keywords

```json
{
  "keywords": ["iphone", "huawei", "xiaomi", "samsung"],
  "maxResultsPerQuery": 100,
  "sort": "most_liked",
  "publishTime": "one_day"
}
```

One row per video; the `searchKeyword` field tells you which competitor surfaced it. Dedup across keywords is automatic.

#### Long-form discovery — pull 5+ minute videos only

```json
{
  "keywords": ["纪录片", "美食纪录片"],
  "maxResultsPerQuery": 200,
  "duration": "over_5m",
  "sort": "most_liked"
}
```

Useful for finding mini-docs, long-form reviews, and series episodes on Douyin (where most content is under 60s).

#### Mass keyword sweep — many narrow topics in one run

```json
{
  "keywords": [
    "麻辣火锅",
    "川菜",
    "粤菜",
    "湘菜",
    "..."
  ],
  "maxResultsPerQuery": 50
}
```

Up to 5 keywords run in parallel. Cross-keyword duplicates are removed automatically, so a video tagged across multiple cuisines appears only once.

#### Keep the MP4s for every search result

```json
{
  "keywords": ["美食", "家常菜"],
  "maxResultsPerQuery": 50,
  "shouldDownloadVideos": true,
  "shouldDownloadCovers": true,
  "videoKvStoreName": "douyin-search-cooking"
}
```

Saves the MP4 + cover image for each matched video to a named, persistent key-value store (`douyin-search-cooking`). MP4 downloads add $0.99 per 1,000 successful saves; cover images are free.

A small share of MP4 downloads can fail on wide sweeps when a video's CDN URL ages out before it's reached. Failed downloads leave `videoFile` as `null` on the affected row; the metadata row still ships and is not charged the download fee.

### Pricing — Pay Per Event (PPE)

**$4.99 per 1,000 results.** Each row written to the dataset counts as one result. No charge for failed pages, retries, or empty keywords.

| Event | Per call | Per 1,000 |
|-------|----------|-----------|
| `result` (one dataset row) | $0.00499 | $4.99 |
| `video_downloaded` (one successful MP4 saved, opt-in) | $0.00099 | $0.99 |

Cover and slideshow image downloads are free. Toggles default OFF — leave them off for pure metadata scraping.

#### Free tier

10 lifetime runs, capped at 12 results per keyword per run. No credit card. Plenty for evaluation; combine 5 keywords × 12 results = a 60-row sample dataset per run.

### FAQ

**How many fields are returned per video?**
62 top-level fields per row, with `authorMeta` containing a further 42 fields nested. Sub-objects (`musicMeta`, `videoMeta`, `statistics`, `permissions`, `commerce`, `share`, `interaction`) and arrays (`hashtags`, `videoTags`, `mentions`, `chapters`) push the total far higher.

**How many results can I expect per keyword?**
Typically 100–300 unique videos before Douyin's search backend stops returning new items, regardless of how high you set `maxResultsPerQuery`. To get more coverage, use multiple related keywords — cross-keyword deduplication is automatic, so you never pay twice for the same video.

**Does the sort/publish/duration filter combine?**
Yes. All filters are applied server-side and stack: `sort=most_liked` + `publishTime=one_week` + `duration=under_1m` returns the most-liked sub-1-minute videos from the last 7 days. Narrow combinations may shrink the result count.

**How fresh is the data?**
Live — every field is fetched on demand at run time. No caching.

**Are the media URLs permanent?**
The `url` (`https://www.douyin.com/video/<id>`) and `shareUrl` are permanent — use them as the long-term reference. Image URLs (`videoMeta.cover`, `authorMeta.avatarLarge` and friends) stay valid for roughly 14–30 days. The video URLs (`videoMeta.playUrl`, `videoMeta.downloadUrl`, `videoMeta.bitRates[].url`) are short-lived — they typically expire within hours; the exact unix-seconds expiry is in `videoMeta.cdnUrlExpiresAt`. If you need long-term media, enable `shouldDownloadVideos` / `shouldDownloadCovers` / `shouldDownloadSlideshowImages` to copy the bytes into your own KV store.

**What's the difference between `hashtags` and `videoTags`?**
`hashtags` are the `#tag`s the creator typed in the caption. `videoTags` is Douyin's own server-classified content taxonomy — for example a video might be tagged `美食` (level 1, top-level category) → `家常菜` (level 2) → `下饭菜` (level 3, leaf). The classification is server-assigned and is one of the more interesting signals on the platform.

**Can I search by hashtag specifically?**
Yes — pass `"#美食"` as a keyword. Douyin's search treats hashtag and free-text searches similarly, and both flow through the same row shape.

**Can I scrape comments / individual posts / a creator's full profile?**
Not in this actor. Search results only. Other actors in this collection cover those use cases — see the navigation table at the top.

**What's the maximum results per keyword?**
1,000. Note that Douyin's own search backend caps relevance results around 200–300 per keyword in practice, so very high values may not fully fill.

**Does the actor work for any Douyin search?**
Public search only. The same surface anyone hits when they search on the Douyin web or app. Results respect Douyin's own region- and age-gating where applicable.

### Support

- **Bugs**: Issues tab
- **Features**: Issues tab

### Legal Compliance

Extracts publicly available data from Douyin (抖音). Users must comply with Douyin's terms of service and applicable data protection regulations (GDPR, CCPA).

***

*Structured Douyin search results — full creator profile, video, music, hashtags, server-classified video tags, engagement stats — one row per match, in clean JSON.*

# Actor input Schema

## `keywords` (type: `array`):

Add one or more keywords. Chinese, English, hashtags, brand names, and emoji all work.<br><br>Each keyword is searched independently; cross-keyword duplicates are removed automatically. A single keyword typically returns 100–300 unique videos before Douyin stops returning new results — combine multiple keywords to get more.

## `maxResultsPerQuery` (type: `integer`):

How many results to fetch for each keyword. Set this based on what you actually need — cost scales linearly.<br><br><ul><li>Default: <code>100</code>. Maximum: <code>1000</code>.</li><li>Douyin caps a single keyword at roughly 100–300 unique items, so values above 300 may not fully fill.</li></ul>

## `sort` (type: `string`):

How Douyin orders results. Leave on <b>Relevance</b> for the standard search ranking.

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

Limit results to videos published within this window.

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

Limit results to videos in this duration range.

## `shouldDownloadVideos` (type: `boolean`):

Save each result's MP4 file to your key-value store. Adds <b>$0.99 per 1,000 successful downloads</b>. Image-text posts have no MP4 — use <b>Download slideshow images</b> instead.<br><br>A small share of downloads can fail when a video's CDN URL ages out before it's reached. Failed downloads leave <code>videoFile</code> as <code>null</code> on the affected row; the metadata row still ships and is not charged the download fee.

## `shouldDownloadCovers` (type: `boolean`):

Save each result's cover image (JPEG) to your key-value store. <b>Free.</b>

## `shouldDownloadSlideshowImages` (type: `boolean`):

For image-text posts, save every slide image to your key-value store. <b>Free.</b> Has no effect on plain video posts.

## `videoKvStoreName` (type: `string`):

Save downloaded MP4s, covers, and slideshow images to a <b>named, persistent</b> key-value store instead of the run's default one. Useful for archiving (the named store survives forever, the default one is cleaned up with the run) and for combining downloads from many runs into one bucket you can reuse later.<br><br><b>Naming rules:</b> lowercase letters, digits, and dashes only.<br><br><b>Common patterns:</b><ul><li><code>douyin-search-videos</code> — single shared archive</li><li><code>douyin-search-2026-q2</code> — partition by quarter</li><li><code>douyin-search-cooking</code> — partition by topic / niche</li></ul>Browse and re-download anything you've saved at <a href="https://console.apify.com/storage/key-value" target="_blank">console.apify.com/storage/key-value</a>.<br><br>Leave empty to use this run's default store.

## Actor input object example

```json
{
  "keywords": [
    "美食",
    "iphone"
  ],
  "maxResultsPerQuery": 100,
  "sort": "general",
  "publishTime": "unlimited",
  "duration": "unlimited",
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "shouldDownloadSlideshowImages": false,
  "videoKvStoreName": ""
}
```

# Actor output Schema

## `results` (type: `string`):

Link to the dataset containing all scraped Douyin search results.

# 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 = {
    "keywords": [
        "美食",
        "iphone"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zen-studio/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 = { "keywords": [
        "美食",
        "iphone",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("zen-studio/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 '{
  "keywords": [
    "美食",
    "iphone"
  ]
}' |
apify call zen-studio/douyin-search-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Douyin 抖音 Search Scraper - Keyword + Filters & 60+ Fields",
        "description": "Extract Douyin (抖音) search results by keyword. One row per video with full creator profile, music, hashtags, video tags, and engagement stats. Filter by sort, publish window, and duration. 60+ fields per video, 46 per creator. Free tier - 10 runs.",
        "version": "0.0",
        "x-build-id": "acaerytaQKpZv4RUm"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/zen-studio~douyin-search-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-zen-studio-douyin-search-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/zen-studio~douyin-search-scraper/runs": {
            "post": {
                "operationId": "runs-sync-zen-studio-douyin-search-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/zen-studio~douyin-search-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-zen-studio-douyin-search-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "keywords"
                ],
                "properties": {
                    "keywords": {
                        "title": "🔎 Search keywords",
                        "type": "array",
                        "description": "Add one or more keywords. Chinese, English, hashtags, brand names, and emoji all work.<br><br>Each keyword is searched independently; cross-keyword duplicates are removed automatically. A single keyword typically returns 100–300 unique videos before Douyin stops returning new results — combine multiple keywords to get more.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResultsPerQuery": {
                        "title": "📺 Maximum results per keyword",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "How many results to fetch for each keyword. Set this based on what you actually need — cost scales linearly.<br><br><ul><li>Default: <code>100</code>. Maximum: <code>1000</code>.</li><li>Douyin caps a single keyword at roughly 100–300 unique items, so values above 300 may not fully fill.</li></ul>",
                        "default": 100
                    },
                    "sort": {
                        "title": "📊 Sort order",
                        "enum": [
                            "general",
                            "most_liked",
                            "latest"
                        ],
                        "type": "string",
                        "description": "How Douyin orders results. Leave on <b>Relevance</b> for the standard search ranking.",
                        "default": "general"
                    },
                    "publishTime": {
                        "title": "📅 Published in",
                        "enum": [
                            "unlimited",
                            "one_day",
                            "one_week",
                            "half_year"
                        ],
                        "type": "string",
                        "description": "Limit results to videos published within this window.",
                        "default": "unlimited"
                    },
                    "duration": {
                        "title": "⏱️ Video duration",
                        "enum": [
                            "unlimited",
                            "under_1m",
                            "one_to_five",
                            "over_5m"
                        ],
                        "type": "string",
                        "description": "Limit results to videos in this duration range.",
                        "default": "unlimited"
                    },
                    "shouldDownloadVideos": {
                        "title": "📥 Download MP4 videos",
                        "type": "boolean",
                        "description": "Save each result's MP4 file to your key-value store. Adds <b>$0.99 per 1,000 successful downloads</b>. Image-text posts have no MP4 — use <b>Download slideshow images</b> instead.<br><br>A small share of downloads can fail when a video's CDN URL ages out before it's reached. Failed downloads leave <code>videoFile</code> as <code>null</code> on the affected row; the metadata row still ships and is not charged the download fee.",
                        "default": false
                    },
                    "shouldDownloadCovers": {
                        "title": "🖼️ Download cover images",
                        "type": "boolean",
                        "description": "Save each result's cover image (JPEG) to your key-value store. <b>Free.</b>",
                        "default": false
                    },
                    "shouldDownloadSlideshowImages": {
                        "title": "🎴 Download slideshow images",
                        "type": "boolean",
                        "description": "For image-text posts, save every slide image to your key-value store. <b>Free.</b> Has no effect on plain video posts.",
                        "default": false
                    },
                    "videoKvStoreName": {
                        "title": "Custom key-value store name",
                        "type": "string",
                        "description": "Save downloaded MP4s, covers, and slideshow images to a <b>named, persistent</b> key-value store instead of the run's default one. Useful for archiving (the named store survives forever, the default one is cleaned up with the run) and for combining downloads from many runs into one bucket you can reuse later.<br><br><b>Naming rules:</b> lowercase letters, digits, and dashes only.<br><br><b>Common patterns:</b><ul><li><code>douyin-search-videos</code> — single shared archive</li><li><code>douyin-search-2026-q2</code> — partition by quarter</li><li><code>douyin-search-cooking</code> — partition by topic / niche</li></ul>Browse and re-download anything you've saved at <a href=\"https://console.apify.com/storage/key-value\" target=\"_blank\">console.apify.com/storage/key-value</a>.<br><br>Leave empty to use this run's default store.",
                        "default": ""
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
