# TikTok Transcript Scraper — Video Subtitles & Captions by URL (`nick.cheng/tiktok-transcript-scraper`) Actor

Get TikTok video transcripts by link or video ID: TikTok's own captions as clean text plus timed segments, with language, author and caption. $0.003 per transcript on every plan. No captions, no charge. No login, no cookies.

- **URL**: https://apify.com/nick.cheng/tiktok-transcript-scraper.md
- **Developed by:** [Nicholas Cheng](https://apify.com/nick.cheng) (community)
- **Categories:** Social media, AI, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 transcript delivereds

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?

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 Transcript Scraper

**Give it TikTok video links or IDs — get back what is said in each video, as clean text with timestamps.** The transcript is TikTok's own caption track for the video, with its language and the creator's handle and caption. No login, no cookies, no proxy configuration. Accepts full links (`tiktok.com/@name/video/…`), share links (`vm.tiktok.com/…`, `tiktok.com/t/…`), or bare 19-digit video IDs.

**You pay only for transcripts that came back.** A video without captions, a photo post, or a deleted or private video produces an explanatory row and costs nothing.

| | |
|---|---|
| **Input** | Video URLs, share links, or numeric video IDs — or a CSV / Google Sheet of them |
| **Output** | One row per transcript: plain text + timed segments + language, author, caption, duration |
| **Price** | **$0.003 per transcript — the same on every Apify plan** |
| **Not charged** | Videos without captions, photo posts, unavailable videos |

***

### What you get

Real output from a run (NASA, `7667244788046892319`):

```json
{
  "inputOrder": 1,
  "itemType": "transcript",
  "videoId": "7667244788046892319",
  "requestedAs": "7667244788046892319",
  "url": "https://www.tiktok.com/@nasa/video/7667244788046892319",
  "authorHandle": "nasa",
  "authorNickname": "NASA",
  "description": "Drop your questions below! 🚀",
  "createdAt": "2026-07-27T16:25:49.000Z",
  "durationSeconds": 13,
  "transcriptLanguage": "eng-US",
  "transcriptType": "auto-generated",
  "transcript": "My name is Jared Isaacman. I'm the administrator of NASA. I don't know anything about TikTok, but my team's got it covered, and they say that you should drop your questions in the chat.",
  "subtitles": [
    {
      "language": "eng-US",
      "type": "auto-generated",
      "text": "My name is Jared Isaacman. I'm the administrator of NASA. I don't know anything about TikTok, but my team's got it covered, and they say that you should drop your questions in the chat.",
      "segments": [
        { "start": 0.02, "end": 1.46, "text": "My name is Jared Isaacman." },
        { "start": 1.461, "end": 3.181, "text": "I'm the administrator of NASA." },
        { "start": 3.182, "end": 5.501, "text": "I don't know anything about TikTok," },
        { "start": 5.502, "end": 6.901, "text": "but my team's got it covered," },
        { "start": 6.902, "end": 9.681, "text": "and they say that you should drop your questions in the chat." }
      ]
    }
  ],
  "subtitlesNote": null
}
```

- `transcript` — the spoken-language track as one string.
- `subtitles` — every caption track TikTok has for the video, each with timed `segments`; `type` is
  `auto-generated` (TikTok's speech recognition) or `machine-translated`.
- `transcriptLanguage` — TikTok's label for the spoken language. It comes from TikTok's own language
  detection, which is occasionally wrong; check it before relying on it.

***

### Input

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@nasa/video/7695090484124929293",
    "https://vm.tiktok.com/ZMabc123/",
    "7514320905909194030"
  ]
}
```

| Option | Notes |
|---|---|
| `videoUrls` | Full links, share links (followed to the final URL), or bare video IDs. De-duplicated |
| `listUrl` | A public `.csv` / `.txt`, or a Google Sheet shared as "Anyone with the link". With several columns, only TikTok links are read |
| `maxConcurrency` | Videos fetched at the same time, 1–10 (default 3) |
| `maxItems` | Hard cap on transcripts for the run |

Every row carries `inputOrder` (its position in your list) so results map back to your sheet. Long lists are a
normal run: throttled videos are retried slowly at the end, and a migrated or resurrected run skips everything
already delivered — never fetched or charged twice.

***

### Pricing

**$0.003 per transcript, on every Apify plan** — Free, Bronze, Silver, Gold, Platinum, Diamond. Check the Pricing
tab: all six columns are identical. No start fee, no per-minute fee.

Charged once per transcript **delivered**. A video that turns out to have no captions is a free row, so the price
you see is the price per transcript you actually get.

#### What you are not charged for

| | What happens here |
|---|---|
| **Videos without captions** | One row with `chargedForThis: false` and the reason. Common for music-only clips and videos without speech. |
| **Photo posts** | No audio, nothing to transcribe — free row. |
| **Unavailable videos** | Deleted, private, or mistyped links — free row with TikTok's own reason. |
| **The free plan** | Same code path, same fields, same price. No demo mode, no row cap. |

***

### What this Actor cannot do

- **No speech recognition of our own.** The transcript is the caption track TikTok generated for the video. If
  TikTok has none, you get none — we do not download the audio and transcribe it. In our own sample of 25
  videos across eleven accounts, 15 had captions.
- **No video lists.** You bring the links; for an account's videos, collect the links first.
- For play, like, comment and share counts, use the
  [TikTok Video Stats Scraper](https://apify.com/nick.cheng/tiktok-video-stats) (it can include the transcript
  too, with `includeSubtitles`).

***

### How it stays working

The video page is fetched exactly as a browser without cookies would fetch it; TikTok lists the video's caption
tracks in the page data, and the caption file is downloaded the same way. There is no login to get banned and no
signature to reverse-engineer. Measured from a datacenter address over three rounds: the same 15 of 25 videos had
captions every round, and all 48 caption downloads returned text.

***

### Integrating

```bash
curl -X POST "https://api.apify.com/v2/acts/nick.cheng~tiktok-transcript-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"videoUrls":["https://www.tiktok.com/@nasa/video/7695090484124929293"]}'
```

Official clients exist for JavaScript and Python; results export as JSON, CSV or Excel; and the Actor is available
as a tool to AI agents through Apify's MCP server.

# Actor input Schema

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

Videos to look up, one row each: play, like, comment, share and save counts plus description, hashtags, music and author. Accepts full links (https://www.tiktok.com/@name/video/123…), share links (vm.tiktok.com/…, tiktok.com/t/…), or bare numeric video IDs. Photo-post links (/photo/…) are accepted and read from the same page data.

## `listUrl` (type: `string`):

Link to a long list of targets: a public .csv or .txt file, or a Google Sheet shared as "Anyone with the link". Read in addition to the fields above and de-duplicated with them. With one value per row, plain names, @handles, profile URLs, video URLs and numeric video IDs are all read. With several columns, only TikTok links and @handles are read — other cells (names, follower counts, emails) are ignored, so no unintended account is ever looked up or charged.

## `maxConcurrency` (type: `integer`):

How many pages are fetched at the same time. Higher is faster on long lists; if TikTok starts throttling, the Actor pauses on its own and retries the throttled targets slowly at the end, so they are not lost or charged as failures.

## `maxItems` (type: `integer`):

Hard ceiling on rows for the whole run, counting profiles and videos together. Leave at 0 for no limit.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@nasa/video/7695090484124929293",
    "https://www.tiktok.com/@duolingo/video/7514320905909194030"
  ],
  "maxConcurrency": 3,
  "maxItems": 0
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "videoUrls": [
        "https://www.tiktok.com/@nasa/video/7695090484124929293",
        "https://www.tiktok.com/@duolingo/video/7514320905909194030"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nick.cheng/tiktok-transcript-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.tiktok.com/@nasa/video/7695090484124929293",
        "https://www.tiktok.com/@duolingo/video/7514320905909194030",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("nick.cheng/tiktok-transcript-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.tiktok.com/@nasa/video/7695090484124929293",
    "https://www.tiktok.com/@duolingo/video/7514320905909194030"
  ]
}' |
apify call nick.cheng/tiktok-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nick.cheng/tiktok-transcript-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/Q1fUCzciq6eAkcdXN/builds/5zOKJzv2PM8gy2fqD/openapi.json
