# Douyin Transcript API – AI Speech to Text & Subtitles (`lance_api/douyin-transcripts-scraper-api`) Actor

Transcribe public Douyin videos into AI-generated text, timestamped segments, SRT, and WebVTT. Supports short links, share text, batch processing, optional translation, and video metadata.

- **URL**: https://apify.com/lance\_api/douyin-transcripts-scraper-api.md
- **Developed by:** [LanceAPI](https://apify.com/lance_api) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.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 Transcripts Scraper API

**Turn public Douyin videos into AI-generated transcripts — even when no native subtitle track is available.**

Submit a public Douyin video URL, short link, copied share text, or aweme ID. Get speech-to-text as plain text, timestamped segments, SRT, WebVTT, or any combination from one transcription pass. Optionally add a translation plus available video, creator, engagement, and temporary media metadata.

This is an unofficial Actor and is not affiliated with or endorsed by Douyin or ByteDance.

### At a glance

- **AI transcription:** creates a transcript directly from spoken audio; no native subtitle track is required.
- **One pass, four formats:** text, timestamped segments, SRT, and WebVTT are generated from the same transcription.
- **Optional translation:** the original-language transcript is always retained.
- **Batch processing:** submit up to 200 URLs in one run.
- **Structured output:** receive Dataset/API records with transcript, status, errors, and optional metadata.
- **Billing:** successful results and started transcription minutes; translation is charged only when requested and completed.

### Quick start

1. Add one or more public Douyin video inputs.
2. Choose the transcript formats you need.
3. Optionally enable translation and choose its target language.
4. Start the Actor and open the Dataset.

```json
{
  "urls": ["https://www.douyin.com/video/7534679152504376595"],
  "formats": ["text", "segments", "srt", "vtt"],
  "translate": false,
  "targetLanguage": "en",
  "includeMediaMetadata": true
}
```

### Short output example

The example below is based on a real public Douyin video. Temporary media URLs are shortened because they expire.

```json
{
  "inputUrl": "0.71 09/04 :9pm K@w.se uSL:/ # 媒体原创 大型机械已推进至西藏吉隆口岸受灾核心区，现场正加快搜寻失联人员的痕迹。# 直击第一线 https://v.douyin.com/mi-Dvafw0HI/ 复制此链接，打开Dou音搜索，直接观看视频！",
  "normalizedUrl": "https://www.douyin.com/jingxuan?modal_id=7680748547309915428",
  "awemeId": "7680748547309915428",
  "success": true,
  "status": "success",
  "content": {
    "id": "7680748547309915428",
    "type": "video",
    "title": "#媒体原创 大型机械已推进至西藏吉隆口岸受灾核心区，现场正加快搜寻失联人员的痕迹。#直击第一线",
    "description": "#媒体原创 大型机械已推进至西藏吉隆口岸受灾核心区，现场正加快搜寻失联人员的痕迹。#直击第一线",
    "publishedAt": "2026-09-02T01:47:12.000Z",
    "durationSeconds": 26.05
  },
  "media": {
    "videoUrl": "https://...",
    "smallVideoUrl": "https://...",
    "audioUrl": null,
    "coverUrl": "https://...",
    "mediaUrlsTemporary": true
  },
  "author": {
    "nickname": "央视网",
    "avatarUrl": "https://...",
    "followerCount": 72894152,
    "totalFavorited": 3325968064
  },
  "engagement": {
    "playCount": 0,
    "likeCount": 1400,
    "commentCount": 44,
    "shareCount": 20,
    "collectCount": 90
  },
  "transcript": {
    "source": "asr",
    "language": "zh",
    "characterCount": 113,
    "text": "我现在验试在吉隆口岸受灾的核心区 这个红色挖机往前大概目测只有20米的距离 这个平台也就是现在有着五星红旗在飘扬的地方 就是此前的吉隆口岸的连检大楼 来自于移民警察还有消防的力量 现在正在人机配合 大家在加快搜寻试炼人员的痕迹",
    "segments": [
      { "id": 0, "start": 0, "end": 3.66, "text": "我现在验试在吉隆口岸受灾的核心区" },
      { "id": 1, "start": 3.66, "end": 8.94, "text": "这个红色挖机往前大概目测只有20米的距离" },
      { "id": 2, "start": 8.94, "end": 13.8, "text": "这个平台也就是现在有着五星红旗在飘扬的地方" },
      { "id": 3, "start": 13.8, "end": 18.28, "text": "就是此前的吉隆口岸的连检大楼" },
      { "id": 4, "start": 18.28, "end": 20.78, "text": "来自于移民警察还有消防的力量" },
      { "id": 5, "start": 20.78, "end": 22.6, "text": "现在正在人机配合" },
      { "id": 6, "start": 22.6, "end": 26.08, "text": "大家在加快搜寻试炼人员的痕迹" }
    ]
  },
  "translation": null,
  "error": null,
  "scrapedAt": "2026-09-02T03:49:38.005Z"
}
```

`playCount: 0` above is a value supplied by Douyin for that item, not a placeholder. Unknown optional numeric metadata is returned as `null`. The example requests `text` and `segments`; `srt` and `vtt` are included when selected.

### Key features

- **Flexible input resolution:** accepts supported URLs, short links, copied share text, and aweme IDs.
- **Canonical deduplication:** equivalent inputs are processed once by aweme ID.
- **Isolated batch failures:** an inaccessible video does not stop the rest of the batch.
- **Optional metadata:** include best-effort content, media, creator, and engagement fields.
- **Dataset/API-ready records:** consume structured transcript, status, and error data in automations.

### Input reference

| Field | Type | Required | Default / Prefill | Limits | Description |
| --- | --- | --- | --- | --- | --- |
| `urls` | array of strings | Yes | Example URL prefilled in Console | 1–200 items | Public Douyin video inputs. Blank strings are ignored. |
| `formats` | array | No | `text`, `segments` | One or more: `text`, `segments`, `srt`, `vtt` | Output formats to derive from the transcript. |
| `translate` | boolean | No | `false` | — | Add a translated transcript without replacing the source transcript. |
| `targetLanguage` | string | No | `en` | One supported target below | Used only when `translate` is `true`. |
| `includeMediaMetadata` | boolean | No | `true` | — | Include available `content`, `media`, `author`, and `engagement` fields. |

#### Translation targets

| Code | Language | Code | Language |
| --- | --- | --- | --- |
| `en` | English | `es` | Spanish |
| `pt` | Portuguese | `fr` | French |
| `de` | German | `it` | Italian |
| `ja` | Japanese | `ko` | Korean |
| `zh-CN` | Chinese (Simplified) | `zh-TW` | Chinese (Traditional) |
| `ar` | Arabic | `hi` | Hindi |
| `ru` | Russian | `id` | Indonesian |
| `tr` | Turkish | `vi` | Vietnamese |
| `th` | Thai | `nl` | Dutch |
| `pl` | Polish | `uk` | Ukrainian |

### Supported Douyin inputs

| Input | Example |
| --- | --- |
| Video URL | `https://www.douyin.com/video/{awemeId}` |
| Note URL | `https://www.douyin.com/note/{awemeId}` |
| Modal URL | `https://www.douyin.com/jingxuan?modal_id={awemeId}` or `https://www.douyin.com/discover?modal_id={awemeId}` |
| Short link | Supported `https://v.douyin.com/...` redirects |
| Copied share text | Any text containing a supported URL |
| Aweme ID | A bare numeric aweme ID |

`/note/` inputs are accepted only when they resolve to a video or other audio-capable post. Search pages, profiles, comments, private content, and image-only posts are not supported.

### Output reference

Each unique resolved aweme ID produces one Dataset record. Results can finish in a different order from the input list, so match records by `inputUrl` or `awemeId` rather than Dataset position.

| Field | Type | Description |
| --- | --- | --- |
| `inputUrl` | string | The submitted input after basic normalization. |
| `normalizedUrl` | string or `null` | Canonical Douyin URL used for resolution when available. |
| `awemeId` | string or `null` | Canonical resolved Douyin content ID. |
| `success` | boolean | Whether transcription succeeded. `true` includes `partial_success`. |
| `status` | string | Processing outcome; see [Status and billing](#status-and-billing). |
| `content` | object or `null` | Video identity, type, title/description, publication time, and duration when metadata is enabled and available. |
| `media` | object or `null` | Direct audio/video/cover URLs and `mediaUrlsTemporary` when enabled and available. |
| `author` | object or `null` | Creator information when enabled and available. |
| `engagement` | object or `null` | Play, like, comment, share, and collect counts when enabled and available. |
| `transcript` | object or `null` | Original-language transcript after successful ASR. |
| `translation` | object or `null` | Optional target-language transcript. |
| `error` | object or `null` | Public error details for unsuccessful or partial items. |
| `scrapedAt` | ISO 8601 string | Time the Dataset item was produced. |

When `includeMediaMetadata` is `false`, `content`, `media`, `author`, and `engagement` are omitted from the record. Metadata is best effort: unavailable fields can be `null`, and temporary direct media URLs may expire.

#### Transcript and translation objects

| Field | Meaning |
| --- | --- |
| `source` | `asr` for the source transcript; `translation` for a translated transcript. |
| `language` | Detected spoken language for `transcript`, or requested target language for `translation`. |
| `characterCount` | Unicode code-point count of complete `text`, including spaces and punctuation. |
| `text` | Full transcript, included when `text` is selected. |
| `segments` | Timed `{ id, start, end, text }` entries in seconds, included when `segments` is selected. |
| `srt` | Complete SubRip document, included when `srt` is selected. |
| `vtt` | Complete WebVTT document, included when `vtt` is selected. |

All selected formats are derived from the same canonical transcript and timestamps. Selecting all four formats creates one transcription job and one transcript charge—not four.

### Translation

Translation starts from the completed source transcript. It never replaces the original transcript and does not send the media through a second transcription pass.

- If `translate` is `false`, `translation` is `null`.
- If the detected language already matches `targetLanguage`, the Actor reuses the source content and creates no translation charge.
- Simplified Chinese (`zh-CN`) and Traditional Chinese (`zh-TW`) are distinct targets.
- If translation fails after a transcript is produced, the item remains usable: `success` is `true`, `status` is `partial_success`, `translation` is `null`, and `error.code` is `TRANSLATION_FAILED`.
- Translation units are calculated from the original transcript's `characterCount`, never the translated character count.

### Status and billing

#### Statuses

| Status | Meaning |
| --- | --- |
| `success` | Transcription and any requested translation completed. |
| `partial_success` | Transcription completed, but optional translation failed. |
| `invalid_input` | The input does not contain a supported Douyin input. |
| `unsupported_url` | The Douyin URL is not a supported, audio-capable content type. |
| `not_found`, `unavailable`, `private_content` | The content cannot be accessed. |
| `blocked`, `rate_limited` | Douyin rejected or throttled the resolver request. |
| `media_resolve_failed`, `media_unavailable`, `no_audio` | No usable media source was produced. |
| `no_speech` | The speech service reported no detectable speech. |
| `transcription_timeout`, `transcription_failed` | Speech recognition did not produce a usable transcript. |
| `upstream_error`, `internal_error` | No more specific safe classification was available. |

For `partial_success`, `error.code` is `TRANSLATION_FAILED`; it is not a top-level `status` value.

#### When events are charged

The Actor uses the billing events `result`, `transcript`, and `translation`.

| Outcome | `transcript` | `result` | `translation` |
| --- | ---: | ---: | ---: |
| Resolution fails before ASR, including `no_audio` | No | No | No |
| ASR is submitted but fails or reports `no_speech` | Yes | No | No |
| Transcript succeeds; no translation requested | Yes | Yes | No |
| Transcript succeeds; translation fails (`partial_success`) | Yes | Yes | No |
| Transcript and required translation succeed | Yes | Yes | Yes |
| Duplicate input resolving to an already processed aweme ID | No | No | No |

Transcript billing begins immediately before the media is submitted to speech recognition, because upstream processing starts at submission. A successful transcript creates a result event even when optional translation later fails. Translation is charged only after the required translation succeeds. Extra requested formats and audio-to-video fallback do not create another transcript event.

### Pricing

| Service | Free | Starter | Scale | Business |
| --- | ---: | ---: | ---: | ---: |
| Successful results / 1,000 | $1.00 | $1.00 | $1.00 | $1.00 |
| Transcript / 1,000 started minutes | $7.00 | $6.50 | $6.00 | $5.00 |
| Translation / started 1,000 source characters | $0.10 | $0.09 | $0.08 | $0.07 |

Prices are applied per event unit: one successful result is $0.001 on every plan; transcript time rounds up to a started minute; translation characters round up to a started 1,000-character unit.

Resolution failures and canonical duplicates are not charged. Once media is submitted to speech recognition, started transcription minutes are chargeable even if transcription later fails or reports no speech.

#### Example 1 — 45-second video, no translation

- Transcript: 1 started minute
- Result: 1 successful result
- Translation: 0 units

On the Free plan: **$0.007 transcript + $0.001 result = $0.008**.

#### Example 2 — 125-second video with translation

125 seconds rounds up to **3 started minutes**. If the source transcript contains 1,650 characters, translation uses **2 started 1,000-character units**. Add one successful result. For example, on the Free plan this is **$0.021 transcript + $0.200 translation + $0.001 result = $0.222**.

### Limits

- The Input Schema accepts 1–200 URLs.
- Non-paying runs can process up to 5 URLs.
- Paying runs can process up to 200 URLs.
- Process public, accessible, audio-capable Douyin posts only.

### API usage

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lance_api/douyin-transcripts-scraper-api').call({
  urls: ['https://www.douyin.com/video/7534679152504376595'],
  formats: ['text', 'segments', 'srt'],
  translate: false,
  includeMediaMetadata: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('lance_api/douyin-transcripts-scraper-api').call(run_input={
    'urls': ['https://www.douyin.com/video/7534679152504376595'],
    'formats': ['text', 'segments'],
    'translate': False,
    'includeMediaMetadata': True,
})
print(client.dataset(run['defaultDatasetId']).list_items().items)
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/lance_api~douyin-transcripts-scraper-api/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://www.douyin.com/video/7534679152504376595"],"formats":["text","segments"]}'
```

For long videos or batches, use the asynchronous Actor API to avoid client-side timeouts.

### Use cases

- Create subtitles or captions for public Douyin videos.
- Feed spoken-video content into AI/LLM workflows, semantic search, or knowledge bases.
- Research creator messaging, themes, and public social-video trends.
- Build searchable archives with timestamps for review and clip finding.
- Localize public-video transcripts for multilingual editorial or research workflows.
- Automate transcript collection in Apify API and MCP-compatible workflows.

### FAQ

#### Does this extract Douyin's own subtitles?

No. The Actor generates a new transcript from spoken audio with AI speech recognition. It does not require or claim a native public subtitle track.

#### Do text, segments, SRT, and WebVTT cost four times?

No. All selected formats come from one ASR pass, so they create one transcript event.

#### Can I translate a video into another language?

Yes. Enable `translate` and choose a supported `targetLanguage`. The source transcript stays in `transcript`; the translated version is returned in `translation`.

#### Is translation charged when the source already uses my target language?

No. The Actor reuses the source transcript and does not create a translation event.

#### What happens if translation fails?

The source transcript is preserved. The item is returned with `success: true`, `status: "partial_success"`, `translation: null`, and a structured translation error; no translation event is charged.

#### Are duplicate inputs charged twice?

No. Inputs resolving to the same aweme ID are processed and charged once.

#### Does it require a Douyin login or Cookie?

No. The Actor is designed for supported public Douyin content and does not require you to provide a Douyin login Cookie.

#### Am I charged if transcription fails?

If resolution fails before media is submitted to speech recognition, there is no transcript charge. Once ASR processing starts, started transcription minutes are billed because upstream processing cost has begun—even if transcription later fails or reports no speech. No successful result event is charged in that case.

#### Why is there no transcript for some public links?

The post may be unavailable, private, unsupported, image-only, missing usable media, or contain no detectable speech. Check `status` and `error` in the Dataset item.

#### Are the media URLs permanent?

No. Direct media URLs are resolved at run time, are marked `mediaUrlsTemporary: true`, and may expire.

#### Can I use a `/note/` link?

Yes, if the note resolves to a video or another audio-capable post. Image-only posts cannot be transcribed.

#### Does metadata failure make the transcript fail?

No. Metadata is best effort. Missing optional fields are returned as `null` when available without changing a successful transcript.

### AI agents and MCP

Use this Actor through the Apify API, or through the Apify MCP Server in compatible AI-agent workflows. The Actor returns structured transcript and status data that an agent can use for downstream analysis, search, or automation.

### Responsible use

Process only public videos you are permitted to use. Respect applicable laws, platform terms, copyright, privacy, and data-protection obligations. Do not submit private content, account credentials, or private cookies.

### Support

For reproducible bug reports, include the public input URL, Apify run ID, item status, and error code. Do not send account credentials or private cookies. Contact <lanceapi2026@hotmail.com> or use the Actor page's issue/support channel.

# Actor input Schema

## `urls` (type: `array`):

Add public Douyin video links to transcribe. Full douyin.com URLs, supported Douyin short links, and copied Douyin share text are accepted. Each item is processed independently, so one invalid or unavailable video does not stop the rest of the batch.

## `formats` (type: `array`):

Choose one or more output formats. Every selected format is generated from the same speech-recognition pass.

## `translate` (type: `boolean`):

Translate the completed transcript into the selected target language. The original transcript is always preserved, so translation adds a version rather than replacing the source text.

## `targetLanguage` (type: `string`):

Choose the translation target. This setting is used only when transcript translation is enabled.

## `includeMediaMetadata` (type: `boolean`):

Include available Douyin content, media, author, and engagement metadata. Turn this off when you only need transcript data and want a smaller, easier-to-process result.

## Actor input object example

```json
{
  "urls": [
    "https://www.douyin.com/video/7680748547309915428"
  ],
  "formats": [
    "text",
    "segments"
  ],
  "translate": false,
  "targetLanguage": "en",
  "includeMediaMetadata": true
}
```

# Actor output Schema

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

No description

# 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 = {
    "urls": [
        "https://www.douyin.com/video/7680748547309915428"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lance_api/douyin-transcripts-scraper-api").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 = { "urls": ["https://www.douyin.com/video/7680748547309915428"] }

# Run the Actor and wait for it to finish
run = client.actor("lance_api/douyin-transcripts-scraper-api").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 '{
  "urls": [
    "https://www.douyin.com/video/7680748547309915428"
  ]
}' |
apify call lance_api/douyin-transcripts-scraper-api --silent --output-dataset

```

## MCP server setup

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

```

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/OhQOlMw4OV98bwTMW/builds/cAK2LaEPghdp9g69K/openapi.json
