# Douyin Video Scraper - Metadata from URLs & Aweme IDs (`khadinakbar/douyin-video-scraper`) Actor

Scrape public Douyin (抖音) videos from URLs, share links, or aweme IDs. Use for China-market research and agents needing one row per video. Not for search or profiles (see sibling Actors). Returns caption, stats, music, hashtags, author, CDN play URL. $0.005/video.

- **URL**: https://apify.com/khadinakbar/douyin-video-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, Videos, MCP servers
- **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 scrapeds

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/actors/running/actors-in-store.md#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 Video Scraper

Turn a public Douyin (抖音) video URL, share link, or numeric aweme ID into one structured metadata row. Paste the identifiers you already have and get caption, like/comment/share/play counts, music, hashtags, author, and the CDN play URL Douyin exposes on the public web page.

This Actor is for China-market researchers, KOL agencies, and AI agents that need a single video's public facts before they branch into search or profile workflows.

### Best fit for this Actor

- Enrich a known list of Douyin video URLs or aweme IDs with public stats and author fields.
- Audit a campaign creative after someone forwards a `v.douyin.com` share link.
- Feed MCP or CRM workflows with one predictable row per video.

Use this Actor when you already have Douyin video URLs, share links, or aweme IDs and need one public metadata row each.

When you need keyword discovery, start at [Douyin Search Scraper](https://apify.com/khadinakbar/douyin-search-scraper). After a video is confirmed, enrich the creator with [Douyin Profile Scraper](https://apify.com/khadinakbar/douyin-profile-scraper). For global TikTok video URLs, use [TikTok Video Scraper](https://apify.com/khadinakbar/tiktok-video-scraper). Comments, Shop SKUs, and MP4 archives stay on dedicated workflows.

### Practical scenario

A cross-border ecommerce analyst pastes `https://www.douyin.com/video/7577614489533680959` and keeps `maxVideos` at `1`. The Actor returns one row: caption, like/play counts, music title, hashtags, author nickname, and a CDN `playUrl`. A deleted or private id finishes `SUCCEEDED` with `VALID_EMPTY` and no `video-scraped` charge. Videos that clear the public bar can then be sent to the profile scraper using `authorProfileUrl`.

### Quick start input

```json
{
  "videoUrls": ["https://www.douyin.com/video/7577614489533680959"],
  "maxVideos": 1
}
```

`videoUrls` accepts canonical `/video/{id}` links, `v.douyin.com` share links, `iesdouyin.com/share/video/{id}` URLs, or a bare 15–21 digit aweme ID. Duplicates are collapsed before any browser navigation.

### Input reference

| Field | Type | What it controls |
|---|---|---|
| `videoUrls` | array (required) | Public Douyin video URLs, share links, or aweme IDs. Example: `https://www.douyin.com/video/7577614489533680959`. Max 50 unique values. |
| `maxVideos` | integer | Hard cap after dedupe. Default 10, max 50. |
| `proxyConfiguration` | object | Defaults to Apify Residential HK. Override only with a CN-capable residential pool. |

### What data you receive

One dataset item is one public Douyin video.

```json
{
  "awemeId": "7577614489533680959",
  "videoUrl": "https://www.douyin.com/video/7577614489533680959",
  "caption": "Example public caption #美食",
  "createTime": "2025-09-04T13:53:20.000Z",
  "durationSec": 15,
  "likeCount": 1200,
  "commentCount": 34,
  "shareCount": 12,
  "playCount": 89000,
  "coverUrl": "https://example.invalid/cover.jpg",
  "playUrl": "https://example.invalid/play.mp4",
  "hashtags": ["美食"],
  "authorNickname": "Creator",
  "authorProfileUrl": "https://www.douyin.com/user/MS4wLjABAAAAexample",
  "scrapedAt": "2025-01-15T12:00:00.000Z",
  "provider": "camoufox"
}
```

| Field | Meaning |
|---|---|
| `awemeId` + `videoUrl` | Stable video id and canonical permalink |
| `likeCount` / `playCount` / `commentCount` / `shareCount` | Public engagement counters when Douyin exposes them |
| `playUrl` / `coverUrl` | CDN URLs from the public payload; they expire and may include a watermark |
| `authorNickname` / `authorProfileUrl` | Public creator identity for a follow-up profile scrape |
| `scrapedAt` / `provider` | Collection time (ISO 8601) and Camoufox route |

`OUTPUT` and `RUN_SUMMARY` in the default key-value store hold `outcome`, `itemsPushed`, and `chargedEventCounts`.

Each row includes a public CDN `playUrl`. This SKU returns metadata plus that link; a separate archive-to-store step is out of contract.

### Use through the API

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~douyin-video-scraper/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"videoUrls":["https://www.douyin.com/video/7577614489533680959"],"maxVideos":1}'
```

Download rows as JSON, CSV, Excel, or HTML from the Dataset tab.

### Use with AI agents through Apify MCP

> Scrape public Douyin video metadata for https://www.douyin.com/video/7577614489533680959. Return awemeId, caption, likeCount, playCount, authorNickname, and videoUrl. Keep the scope to one public video.

Connect via <https://mcp.apify.com>. Read `OUTPUT.outcome` and `itemsPushed` to interpret empty datasets. Cost signal: about `$0.005` per returned video plus platform usage. Deleted or private videos surface as `VALID_EMPTY` without a `video-scraped` charge.

### Connect the workflow

- After you confirm a video, enrich the creator with [Douyin Profile Scraper](https://apify.com/khadinakbar/douyin-profile-scraper).
- When you still need video URLs, discover them with [Douyin Search Scraper](https://apify.com/khadinakbar/douyin-search-scraper).
- For global TikTok rather than 抖音, use [TikTok Video Scraper](https://apify.com/khadinakbar/tiktok-video-scraper).

### Pricing

This Actor uses Pay per event plus Apify platform usage. The live Pricing tab is the current source of truth for billing details.

- `apify-actor-start`: $0.00005 per run
- `video-scraped`: **$0.005** per returned video metadata row

A one-video prefill is about $0.005 in result events plus Camoufox / residential platform usage. 10 rows ≈ $0.05 in `video-scraped` events before platform usage. Invalid input and unavailable videos have no `video-scraped` charge.

### How it works

1. Normalize and deduplicate video URLs, share links, and aweme IDs.
2. Warm up `douyin.com` in Camoufox, then open `/video/{awemeId}`.
3. Intercept `/aweme/v1/web/aweme/detail/` (with RENDER\_DATA / router fallback).
4. Charge `video-scraped` for found rows, then write the dataset item.

### Reliability

Camoufox with Apify Residential HK → SG → TW → JP → MO is the default recovery path for Douyin's signed web payload. When every country still shows the captcha interstitial, the Actor finishes `UPSTREAM_FAILED` with zero billed rows — retry later or supply a CN-capable residential proxy. Deleted or private videos finish `SUCCEEDED` with `VALID_EMPTY`.

### Best results

- Pass public `/video/{id}` URLs, share links, or numeric aweme IDs.
- Keep `maxVideos` at 1–3 while you confirm a proxy path.
- Supply a CN-capable residential proxy when Apify Residential HK/SG/TW/JP/MO hits the captcha interstitial.
- A deleted id finishes `SUCCEEDED` with `VALID_EMPTY` and no video charge.

### Evidence and freshness

Public fields come from Douyin's signed `aweme/detail` payload at scrape time (`scrapedAt` is ISO 8601). CDN `playUrl` values expire. Treat each result as a fresh public snapshot.

### Builder's note

I found that Douyin search is often captcha-walled from default Apify Residential pools, but a direct video page can still expose the signed `aweme/detail` XHR after a homepage cookie warmup — the same Camoufox path that already works for public Douyin profiles. Keeping this Actor to one verb (URL/ID → one metadata row) lets agents call search or profile siblings only when they need those jobs, and keeps charging on metadata rows because the CDN URL already covers playback.

### Legal and responsible use

Use this Actor on public Douyin web data you are authorized to process, follow applicable law and Douyin's terms, and keep the output in your own compliance workflow. Douyin and 抖音 are trademarks of ByteDance. This Actor is independent of Douyin / ByteDance.

Issues and feature requests: use the Actor Issues tab on Apify.

# Actor input Schema

## `videoUrls` (type: `array`):

Douyin videos to scrape. Accepts https://www.douyin.com/video/7577614489533680959, https://v.douyin.com/iAbc123/ share links, iesdouyin.com share URLs, or a bare 15–21 digit aweme ID. One value per row. Default empty is rejected. NOT a profile URL, search keyword, or TikTok link — use douyin-profile-scraper, douyin-search-scraper, or tiktok-video-scraper instead.

## `maxVideos` (type: `integer`):

Hard cap on unique videos processed this run after dedupe. Acts as a cost cap. Bounded 1–50. Default 10. Does not raise Douyin's public availability — private or deleted videos still return no billed row.

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

Default uses Apify Residential with country rotation HK → SG → TW → JP → MO. Douyin is geo-sensitive and mainland CN IPs are not in the Apify Residential pool. Override only if you have a higher-quality CN-region residential pool. Not a Douyin login cookie field.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.douyin.com/video/7577614489533680959",
    "7577614489533680959"
  ],
  "maxVideos": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "HK"
  }
}
```

# Actor output Schema

## `videos` (type: `string`):

One row per public Douyin video with caption, stats, music, hashtags, and author.

## `runSummary` (type: `string`):

Detailed diagnostics, proxy country, failure reasons, and estimated PPE cost.

## `output` (type: `string`):

Compact machine contract: outcome, message, itemsPushed, chargedEventCounts.

# 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 = {
    "videoUrls": [
        "https://www.douyin.com/video/7577614489533680959"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "HK"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/douyin-video-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 = {
    "videoUrls": ["https://www.douyin.com/video/7577614489533680959"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "HK",
    },
}

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

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

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

```

## CLI example

```bash
echo '{
  "videoUrls": [
    "https://www.douyin.com/video/7577614489533680959"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "HK"
  }
}' |
apify call khadinakbar/douyin-video-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/douyin-video-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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