# Douyin Profile Scraper 抖音 Videos, Followers & Stats (`gatherworks/douyin-profile-scraper`) Actor

Scrape any Douyin (抖音) creator profile plus their videos. Followers, likes, plays, comments, shares, hashtags, music and engagement rate on every row. Paste profile URLs. Export to JSON, CSV or Excel. No login, no cookies, no API key.

- **URL**: https://apify.com/gatherworks/douyin-profile-scraper.md
- **Developed by:** [GatherWorks](https://apify.com/gatherworks) (community)
- **Categories:**
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Profile Scraper 抖音 Videos, Followers & Stats

**Paste a Douyin creator link and get the creator plus their videos — followers,
total likes and video count on the profile row, then likes, comments, shares and
saves on every video row.**

**No account, no cookies, no API key.** Paste profile links and run.

***

### 🔍 What is the Douyin Profile Scraper?

Give it Douyin (抖音) profile URLs, copied from the app or the web. For each
creator a normal run returns:

- 👤 the profile — followers, following, video count, total likes received
- 📊 an average-likes-per-video figure, computed for you
- 🎬 their videos — likes, comments, shares, saves, and the hashtags and music
  from each one

Everything comes back in one dataset, one row per creator and one row per video.

### ⚡ What can it do?

- **👥 Take many creators at once** and return one dataset covering all of them.
- **🎬 Return the profile and the posts together**, so you can see the audience
  and what that audience actually reacts to in the same export.
- **📊 Rank by output, not just audience.** Every creator carries
  `averageLikesPerVideo`, which is what separates a real audience from a big
  follower number.
- **🔢 Filter by likes** and ignore the long tail.
- **📅 Filter by date.** Keep only videos inside a window you set.
- **🚧 Cap how far a filter searches**, so a narrow filter stops rather than
  running away with your budget.
- **🙅 Or switch the videos off** and take the profile row alone, if that is all
  you need.
- **🌏 Handle Chinese text properly** — bios, captions and hashtags come back as
  written.
- **📄 Export anywhere.** JSON, CSV, Excel — the dataset is yours.

#### 🎯 Average likes per video, calculated for you

Follower counts flatter dormant accounts. Every creator row carries
`averageLikesPerVideo` — lifetime likes divided by videos published — so a
shortlist sorts itself the moment it lands, without an export to a spreadsheet
first.

### ⚡ Speed and accuracy

**Speed.** Measured on a real run: **1 creator and 6 videos in 8 seconds**.

**Accuracy.** Counts are numbers, not display text. Timestamps are ISO 8601.
Hashtags come from each video's own entity list rather than a regex over the
caption. Video links are canonical `douyin.com` permalinks rather than share
wrappers, so they still work when pasted elsewhere. A profile link that does not
resolve is reported and skipped rather than returned empty.

### 📊 What data does it return?

**Creator rows** (`rowType: "creator"`) — one per profile you paste in:

| Field | Notes |
|---|---|
| 🏷️ `displayName` | The creator's name |
| 🔗 `profileUrl` | Canonical link to the profile |
| 📝 `bioText` | The bio text |
| 🔢 `followersCount`, `followsCount`, `videosCount` | Audience and output, as numbers |
| 📊 `totalLikes`, `averageLikesPerVideo` | Lifetime likes, and likes per video |
| ⚖️ `followerRatio` | Followers divided by following |
| ✅ `isVerified`, 🚩 `isPrivate` | Account state |

**Video rows** (`rowType: "video"`) — one per video kept, on a normal run:

| Field | Notes |
|---|---|
| 📝 `videoCaption`, `captionLength` | The caption and its length |
| 🔗 `videoUrl` | Canonical permalink to the video |
| 📊 `likesCount`, `commentsCount`, `sharesCount`, `savesCount` | Engagement, as numbers |
| 📈 `engagementTotal` | Likes, comments, shares and saves added together |
| ⏱️ `durationSeconds` | Video length |
| 🏷️ `hashtags`, `mentions` | Lifted from the caption's entity list |
| 🎵 `musicTitle`, `musicAuthor` | The sound used |
| 📅 `publishedAt` | When it was posted, ISO 8601 |

#### 🚫 What it does **not** return

- **Play counts.** Douyin does not publish them, so this Actor does not invent
  one. Likes, comments, shares and saves are all returned.
- **Anything from a private account.** Its videos are not publicly visible.
- **Follower lists.** Audience size is a number; the individual followers are not returned.
- **Analytics only the account owner can see.**

### 💰 How much does it cost?

You pay per row returned, for what the run actually produces — never for runtime,
and never on a subscription.

**One price, every row: 💵 $0.0034.** A creator row and a video row cost exactly
the same, so a run's cost is simply how many rows you asked for.

| Run | Rows | Cost |
|---|---|---|
| 🟩 1 creator + 30 videos *(a typical run)* | 31 | 💵 $0.11 |
| 🟨 10 creators + 50 videos each | 510 | 💵 $1.73 |
| 🟧 100 creators, videos switched off | 100 | 💵 $0.34 |

**A profile link that does not resolve is free.** So is a video your filters
remove. **A month you do not run it costs nothing at all** — there is no plan to
keep alive.

#### What you get for that

| | Included here |
|---|---|
| 📊 Average likes per video, per creator | ✅ |
| 🔗 Canonical permalinks, not share wrappers | ✅ |
| 🏷️ Hashtags and mentions as arrays | ✅ free |
| 🎵 Music title and author | ✅ free |
| 🔎 Like and date filters | ✅ free |
| 💳 Minimum spend | none |

### 🚀 How do I use it?

1. Paste one or more **Douyin profile URLs**.
2. Run as-is — you get each creator's profile row and their videos.
3. Set **maximum videos per creator** to control how many video rows you get.
4. Optionally set a likes or date filter, or switch **videos** off entirely for
   the profile row alone.
5. Run, then export the dataset as JSON, CSV or Excel.

### ⚙️ Input

| Field | Notes |
|---|---|
| 👤 `profileUrls` | Douyin profile URLs or bare user IDs |
| 🎬 `includeVideos` | Collect their videos. **On by default** |
| 🔢 `maxVideosPerCreator` | How many videos to return per creator |
| 🔢 `minLikes` | Keep only videos with at least this many likes |
| 📅 `postedAfter`, `postedBefore` | Keep only videos inside this window |
| 🚧 `maxScanned` | How far a filter may search before stopping |

```json
{
  "profileUrls": ["https://www.douyin.com/user/MS4wLjABAAAAYzPQIYcktp42pZqL…"],
  "includeVideos": true,
  "maxVideosPerCreator": 50
}
```

### 📄 Output example

Real rows, captured from a live run. Each creator row is followed by that
creator's video rows, and every row is billed the same.

```json
[
  {
    "rowType": "creator",
    "displayName": "碗仔",
    "followersCount": 209950,
    "videosCount": 67,
    "totalLikes": 1822383,
    "averageLikesPerVideo": 27200
  },
  {
    "rowType": "video",
    "videoUrl": "https://www.douyin.com/video/7661485371678873926",
    "likesCount": 258743,
    "commentsCount": 7555,
    "savesCount": 37706,
    "engagementTotal": 404057
  }
]
```

### ❓ Frequently asked questions

**Do I need a Douyin account?** No. No account, no cookies, no API key.

**What do I paste in?** The creator's profile link from the app or the web. A
bare user ID works too.

**Why is there no play count?** Douyin does not publish plays publicly. Rather
than return a zero that looks like data, the field is left out.

**Does it return videos?** Yes — that is the default. Every creator you paste in
comes back with their posts, and each row costs the same as the profile row. Turn
**🎬 Include their videos** off if you only want the profile.

**How do I keep the cost down?** Lower **maximum videos per creator**, or add a
likes or date filter. You are charged per row returned, so fewer rows is less
money, and a filtered-out video is never charged for.

**Can I get the comments on a video?** That is a different job — use the Douyin
Video Scraper, which takes video URLs.

### 🏷️ Pricing

Pay per event — you are charged for output, not for platform time.

| Event | Price | Covers |
|---|---|---|
| 📦 `result` — **primary** | 💵 $0.0034 | Any row returned, creator or video, at one price |
| ▶️ `apify-actor-start` | 💵 $0.00005 | Starting one run, charged once per GB of memory |
| 🔗 Follower and like counts | ✅ **free** | On every creator row |
| 🔎 Filtering and sorting | ✅ **free** | Filtered-out videos are not charged for |
| ❌ User ids that do not resolve | ✅ **free** | Reported, never charged |

**One event, one price.** There is nothing to add on and nothing to switch on:
whatever the run returns, every row costs the same, so you can work out the bill
before you press the button.

#### 🏅 Rates by tier

The prices above are the standard rate. Higher Apify plans are billed at the
discounted tiers below, automatically:

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| 📦 `result` | 💵 $0.0034 | 💵 $0.0029 | 💵 $0.0025 | 💵 $0.0020 |
| ▶️ `apify-actor-start` | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 |

#### 🛑 You are never billed past your limit

Set a maximum charge on the run and the Actor stops when it reaches it, with
every creator collected up to that point complete and saved. Filtered-out videos
are never stored and never billed.

# Actor input Schema

## `profileUrls` (type: `array`):

Paste creator links straight from the app or the web, for example <code>https://www.douyin.com/user/MS4wLjABAAAA…</code>. A bare user ID works too.

## `includeVideos` (type: `boolean`):

Collect the videos each creator published. <b>On by default</b> — switch it off to return the profile row alone.

## `maxVideosPerCreator` (type: `integer`):

Caps how many videos are returned for each creator. Cost scales linearly with this number.

## `minLikes` (type: `integer`):

Keep only videos with at least this many likes.

## `postedAfter` (type: `string`):

Keep only videos published on or after this date.

## `postedBefore` (type: `string`):

Keep only videos published on or before this date.

## `maxScanned` (type: `integer`):

Safety cap on how many videos are examined while filtering, so a narrow filter cannot run away with your budget.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.douyin.com/user/MS4wLjABAAAAYzPQIYcktp42pZqLOu1AnaATM50QzFbECWhKR_gV_yfxMiyzYCNbGoujy8nrcceL"
  ],
  "includeVideos": true,
  "maxVideosPerCreator": 50,
  "maxScanned": 1000
}
```

# Actor output Schema

## `creators` (type: `string`):

One row per creator, each followed by a row per video with likes, comments, shares and saves. Switch the videos off to return the creator rows alone.

# 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 = {
    "profileUrls": [
        "https://www.douyin.com/user/MS4wLjABAAAAYzPQIYcktp42pZqLOu1AnaATM50QzFbECWhKR_gV_yfxMiyzYCNbGoujy8nrcceL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gatherworks/douyin-profile-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 = { "profileUrls": ["https://www.douyin.com/user/MS4wLjABAAAAYzPQIYcktp42pZqLOu1AnaATM50QzFbECWhKR_gV_yfxMiyzYCNbGoujy8nrcceL"] }

# Run the Actor and wait for it to finish
run = client.actor("gatherworks/douyin-profile-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 '{
  "profileUrls": [
    "https://www.douyin.com/user/MS4wLjABAAAAYzPQIYcktp42pZqLOu1AnaATM50QzFbECWhKR_gV_yfxMiyzYCNbGoujy8nrcceL"
  ]
}' |
apify call gatherworks/douyin-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gatherworks/douyin-profile-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/oVJtygi06ZI39O0bq/builds/phAygA3pFZvAsd1i3/openapi.json
