# TikTok Video Subtitle & Transcript Extractor (`vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor`) Actor

Pull every subtitle track off a TikTok video - auto speech recognition plus any machine-translated languages - as timestamped segments and a plain-text transcript.

- **URL**: https://apify.com/vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## TikTok Video Subtitle & Transcript Extractor

Pull the captions TikTok already has for a public video — automatic speech recognition, the creator's own caption track, and TikTok's machine translations — as timestamped segments and a clean plain-text transcript. Paste a batch of video URLs or IDs and get one row per language, with source flags, available languages, video metadata and optional VTT/SRT output. No account, login, cookies, or proxy setup.

### What this actor does

- Accepts full TikTok video URLs, `@user/photo` URLs, short share links, and bare numeric video IDs; duplicates are processed once
- Returns one row per language, not one row per raw caption file
- Reads both WebVTT captions and TikTok's creator-caption JSON format, so manually authored captions are not lost
- Classifies every track from TikTok's raw labels as automatic, machine-translated, or creator-provided, with `isAutoGenerated`, `isOriginalCaption`, and `isTranslation`
- Lists `availableLanguages` on every row and keeps the original language first
- Includes the video's author, caption, publish date, duration, post type, and engagement counts
- Can request TikTok's machine translations for listed languages (`languages`) or all 20 supported targets (`includeAllTranslations`); coverage varies by video and is best-effort
- Can include ready-to-use `vtt` and `srt` fields
- Can transcribe videos that have no captions with an optional local Whisper fallback; language detection is best-effort
- Empty fields are omitted; the dataset never contains nulls, empty strings, or placeholder rows

### Output per transcript row

- `postId` — TikTok video ID
- `postUrl` — canonical video URL
- `username` — author's TikTok username
- `displayName` — author's display name
- `caption` — video description or caption
- `createdAt` — publish timestamp (ISO 8601 UTC)
- `duration` — video duration in seconds
- `postType` — `video` or `slideshow`
- `authorId` — TikTok author ID
- `authorVerified` — whether the author is verified
- `playCount`, `likeCount`, `commentCount`, `shareCount`, `collectCount` — engagement counts
- `languageCode` — TikTok subtitle language code (e.g. `eng-US`, `spa-ES`, `urd-PK`)
- `languageId` — TikTok's internal language ID
- `originalLanguageCode` — the video's original spoken-language code (e.g. `en`, `ur`, `my`)
- `availableLanguages` — every subtitle language obtained for the video
- `subtitleFormat` — `webvtt`, `creator_caption`, or `whisper_asr`
- `source` — raw source code: `ASR`, `MT`, `LC`, `MU`, or `Whisper`
- `sourceType` — `automatic`, `machine_translation`, `creator`, or `unknown`
- `isAutoGenerated`, `isOriginalCaption`, `isTranslation` — TikTok's flags, copied per track
- `version`, `variant` — TikTok's subtitle version and variant labels
- `subtitleUrl` — direct signed subtitle file URL (expires)
- `subtitleUrlExpiresAt` — expiry of that URL (ISO 8601 UTC)
- `segments` — `[{ "start": 0.0, "end": 2.5, "text": "..." }, ...]` with seconds
- `segmentCount` — number of cues
- `transcript` — full joined plain-text transcript
- `transcriptDuration` — end time of the last cue in seconds
- `wordCount` — approximate whitespace-delimited word count
- `vtt`, `srt` — optional subtitle files when those toggles are on
- `scrapedAt` — collection time (ISO 8601 UTC)

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `postUrls` | array of strings | — | TikTok video URLs, photo URLs, short share links, or bare IDs. Duplicates are processed once. |
| `postIds` | array of strings | — | Numeric video IDs as an alternative to `postUrls`. |
| `languages` | array of strings | – | Languages to keep. Accepts TikTok codes (`eng-US`, `spa-ES`) and ISO/English aliases (`en`, `English`, `es`). Missing languages that TikTok can translate are requested best-effort (20 targets total); other values only filter. A filter that matches nothing yields no row and is reported as `no_transcript`. Empty means every track on the default page. |
| `includeAllTranslations` | boolean | `false` | Request TikTok's machine translation for every supported target language. Best-effort and slower; not every target exists for every video. |
| `includeVtt` | boolean | `false` | Include WebVTT text in each row. |
| `includeSrt` | boolean | `false` | Include generated SRT text in each row. |
| `useWhisperFallback` | boolean | `false` | Transcribe videos with no native captions using local Whisper. Roughly 1–3 minutes per short video including model load (longer videos add transcription time); detected language is best-effort. |

#### Example: all native tracks for a video

```json
{
  "postUrls": ["https://www.tiktok.com/@natgeo/video/7637581966396656909"]
}
```

#### Example: manual and translated captions

```json
{
  "postUrls": [
    "https://www.tiktok.com/@asapscience/video/7642449638045256978",
    "https://www.tiktok.com/@blingbeauty85/video/7631960233966832918"
  ],
  "includeVtt": true,
  "includeSrt": true
}
```

#### Example: only Spanish, with a best-effort translation

```json
{
  "postUrls": ["https://www.tiktok.com/@natgeo/video/7637581966396656909"],
  "languages": ["es"]
}
```

#### Example: every available translation

```json
{
  "postIds": ["7631960233966832918"],
  "includeAllTranslations": true,
  "includeVtt": true
}
```

#### Example: no-caption video with Whisper

```json
{
  "postUrls": ["https://www.tiktok.com/@_readultery_/video/7544740407691791623"],
  "useWhisperFallback": true
}
```

### Use cases

- **Content repurposing** — turn a batch of TikToks into blog posts, newsletters, or scripts using the transcript field
- **Multi-language research** — compare the original wording with TikTok's translations across markets
- **Accessibility and compliance** — archive captions and timed segments for audits or caption-quality reviews
- **Social listening** — search what creators actually say, beyond the text caption
- **Translation and dubbing pipelines** — feed timestamped segments into translation or voice tools
- **Creator research** — collect every video's available languages and caption provenance at scale

### FAQ

**Do I need a TikTok account or cookies?**
No. The actor reads public pages and public subtitle files without authentication.

**Why does one video produce more rows than another?**
One row is emitted per language obtained. A video with only its original caption produces one row; a video with an original track plus a translation produces two. Slideshows usually have no caption track, and videos without captions produce no rows unless Whisper is enabled. Caption coverage is not universal: in an independent October 2026 sample of 391 public videos across niches, 47.6% had at least one native caption track (51.8% excluding slideshows).

**What is the difference between ASR, MT, LC, and MU?**
`ASR` is TikTok's automatic speech recognition. `MT` is normally a machine translation. `LC` is TikTok's label on the creator-caption tracks seen in this actor; `MU` is another label TikTok uses on the converted WebVTT twin of those tracks. Because those raw labels are not perfectly documented, use `sourceType`, `isAutoGenerated`, `isOriginalCaption`, and `isTranslation` for filtering. A small number of original-language tracks are labelled `MT` by TikTok (version `whisper_lid`); the actor preserves that raw label, so `isOriginalCaption` can be true on the same row as `isTranslation`. Use `originalLanguageCode`/`languageCode` to identify the original.

**Why do some translations not appear?**
TikTok does not precompute every target language for every video. The actor requests English and Spanish through TikTok's translation endpoint and a fixed set of 18 more targets by refetching the video with the requested locale. Targets outside that set (for example German or Japanese) are not requested, even if TikTok's player lists them. The actor reports only the languages it actually obtained and never fabricates a track.

**Why is `subtitleUrl` missing or expired?**
Native subtitle files are signed links that usually expire in about 48 hours. Links returned by TikTok's translation endpoint expire in about 6 hours. `subtitleUrlExpiresAt` gives the exact expiry for each row. The parsed `segments` and `transcript` are stored in the dataset permanently; use `includeVtt` or `includeSrt` if you need a portable file.

**What happens when a video has no captions?**
No dataset row is added by default. The run status and the `ERRORS` key-value record report `no_transcript`. If a `languages` filter removes every available track, the video is also reported as `no_transcript`. Enable `useWhisperFallback` to transcribe the audio instead. Other `ERRORS` reasons are `invalid`, `private`, `unavailable`, `blocked`, `fetch_failed`, `parse_failed`, and `translation_unavailable`.

**Does Whisper detect the language reliably?**
Not always. It is best on clear, longer speech; short or mixed-language clips can be mislabeled. The detected code is reported on the row and should be treated as a hint.

**Can I scrape private, deleted, or region-restricted videos?**
No. Those videos do not expose a public video record, so they are reported as unavailable and no row is added.

**How fresh is the data?**
Captions, metadata, and translation availability are read when the run executes. A video may gain captions or translations later; run it again to pick them up.

**Is this affiliated with TikTok?**
No. This is a third-party actor using publicly available TikTok pages and subtitle files.

# Actor input Schema

## `postUrls` (type: `array`):

TikTok video URLs to process. Full video URLs, @user/photo URLs, short share links, and bare numeric IDs are accepted. Duplicate IDs are processed once.

## `postIds` (type: `array`):

Numeric TikTok video IDs as strings, as an alternative to postUrls.

## `languages` (type: `array`):

Optional language filter. Accepts TikTok codes (eng-US, spa-ES) and ISO/English aliases (en, English, es, Spanish). Listed languages missing from the video are requested as best-effort TikTok translations. Leave empty for every track on the default page.

## `includeAllTranslations` (type: `boolean`):

Best-effort: request TikTok's machine translation for every supported target language. Coverage varies by video and this adds up to 20 extra requests per video.

## `includeVtt` (type: `boolean`):

Include the original or generated WebVTT text in each transcript row.

## `includeSrt` (type: `boolean`):

Include generated SRT subtitles in each transcript row.

## `useWhisperFallback` (type: `boolean`):

Transcribe videos with no native captions using local Whisper. Slower and opt-in; detected language is best-effort, especially on short clips.

## Actor input object example

```json
{
  "postUrls": [
    "https://www.tiktok.com/@asapscience/video/7642449638045256978"
  ],
  "languages": [],
  "includeAllTranslations": false,
  "includeVtt": false,
  "includeSrt": false,
  "useWhisperFallback": false
}
```

# Actor output Schema

## `transcripts` (type: `string`):

Dataset containing all transcripts extracted from TikTok videos

# 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 = {
    "postUrls": [
        "https://www.tiktok.com/@asapscience/video/7642449638045256978"
    ],
    "languages": [],
    "includeAllTranslations": false,
    "includeVtt": false,
    "includeSrt": false,
    "useWhisperFallback": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor").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 = {
    "postUrls": ["https://www.tiktok.com/@asapscience/video/7642449638045256978"],
    "languages": [],
    "includeAllTranslations": False,
    "includeVtt": False,
    "includeSrt": False,
    "useWhisperFallback": False,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor").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 '{
  "postUrls": [
    "https://www.tiktok.com/@asapscience/video/7642449638045256978"
  ],
  "languages": [],
  "includeAllTranslations": false,
  "includeVtt": false,
  "includeSrt": false,
  "useWhisperFallback": false
}' |
apify call vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/tiktok-video-subtitle-and-transcript-extractor"
        }
    }
}
```

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/6pQ65KR9K8cz8V4OA/builds/sV6PG2PO8kfbf5pyj/openapi.json
