# TikTok Transcript Extractor (`dami_studio/tiktok-transcript-scraper`) Actor

TikTok transcript extractor and scraper API for the spoken text of TikTok videos: send links, get the full transcript, timed segments, SRT and WebVTT files, the track's language, plus video id, author, caption and play count. A video with no caption track is not charged. $0.40 per 1,000 transcripts.

- **URL**: https://apify.com/dami_studio/tiktok-transcript-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Social media, Videos, AI
- **Features:** Limited permissions
- **Stats:** 6 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.38 / 1,000 transcripts

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 for the spoken words in TikTok videos**: paste links and get the full text,
the same text as timed segments, and ready-made SRT and WebVTT files. Each row also carries the
video id, author, caption, hashtags, duration, play count and the language the track is in.

The thing to know before you plan a run: this reads the caption track TikTok already holds for a
video. It does not listen to audio. A video with no caption track has nothing to give, and you get
an uncharged row saying so. In a 120-video sample pulled from TikTok's own topic pages, 85 had a
caption track and 35 did not.

| | |
|---|---|
| **Input** | Video links, `vm.`/`vt.` share links, or bare video ids |
| **Output** | One row per transcript: full text, timed segments, SRT, WebVTT, language flags, and the video's id, author, caption, hashtags, length and counts |
| **Ceiling** | 1,000 links in, 5,000 transcripts per run |
| **Account needed** | None |
| **Price** | $0.40 per 1,000 transcripts on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 12,500 |

### 🔍 What TikTok Transcript Scraper does

It reads each video's caption track and turns it into four shapes of the same thing: one block of
`text`, an array of `segments` with start and end times, an `srt` string and a `vtt` string. Drop
the SRT straight into an editor, or work off the segments.

TikTok makes a caption track itself when it hears speech, and creators can upload their own. Where
TikTok also holds a translated track you can ask for it with `language`, and the row comes back
marked `isTranslated: true`. When there is no translation you get the original rather than an error.

### 📋 What data you get from each TikTok transcript

| What you get | Field |
|---|---|
| Video id, the canonical link and what you pasted | `videoId`, `url`, `inputUrl` |
| Author handle, name and profile link | `authorUsername`, `authorName`, `authorUrl` |
| Caption, hashtags, length and post date | `caption`, `hashtags`, `durationSeconds`, `createdAt` |
| The whole transcript as one block, with word and character counts | `text`, `wordCount`, `characterCount` |
| Timed segments | `segments`, `segmentCount` |
| Subtitle files, ready to save | `srt`, `vtt` |
| Which track it is: language, made by TikTok or uploaded, translated or not | `language`, `languageCode`, `languageName`, `isAutoGenerated`, `isTranslated`, `captionSource` |
| Every caption track the video offered | `availableLanguages` |
| Plays, likes, comments and shares | `playCount`, `likeCount`, `commentCount`, `shareCount` |
| Sound title and cover image | `musicTitle`, `coverUrl` |

### ▶️ How to scrape TikTok transcripts

1. Open [TikTok Transcript Scraper](https://apify.com/dami_studio/tiktok-transcript-scraper) and
   click **Try for free**.
2. Paste your links into **TikTok videos**, one per line, replacing the two examples.
3. Leave **Preferred language** empty for the original words, or put a code like `es` in it.
4. Set **Maximum transcripts** low for the first run, then click **Start**.
5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.

Start it with the input empty and you get one labelled sample row and nothing else.

### 💰 How much does it cost to scrape TikTok transcripts?

**$0.40 per 1,000 transcripts** on the Free plan. Paid plans pay a little less: $0.395 on Starter, $0.39 on Scale and $0.385 on Business. On the free plan, the $5
Apify gives you each month covers about 12,500 transcripts.

You are charged per transcript delivered. A video with no caption track, a deleted or private one, a
line that was not a link, and the sample row are all uncharged. Links past your `maxItems` are never
opened.

One thing to watch: the same video pasted twice, once as a share link and once as a full link, is
read twice and counts twice. Paste one form per video.

### 📥 What you give it

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766",
    "7516208601434819862"
  ],
  "maxItems": 10,
  "language": ""
}
```

| Field | Default | What it is |
|---|---|---|
| `videoUrls` | none (the box holds two example links) | Full links, `vm.`/`vt.` share links or bare numeric ids, mixed freely. Up to 1,000 per run. |
| `maxItems` | none (the box holds `10`) | How many transcripts to return, up to 5,000. The list is read in order and the run stops when it has enough, so links past that point cost nothing. |
| `language` | empty | A code like `es`, `fr`, `de` or `ja`. You get the translated track where TikTok has one, the original where it does not. |
| `concurrency` | `6` | How many videos are read at once, up to 12. Lower it for a very long list. |
| `sessionCookies` | none | Optional: your own session, used only for your run. You are responsible for using it within the site's terms. Anyone holding that value can act as your account, so treat it like a password. The field is stored encrypted. |
| `proxyUrls` | none | Optional. Your own servers, as `http://user:pass@host:port`, used exactly as given. |

### 📤 What you get back

A real row from a recent run. The long fields and one name carrying emoji are cut short here:

```json
{
  "ok": true,
  "charged": true,
  "recordType": "transcript",
  "videoId": "7657803613355412766",
  "url": "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766",
  "authorUsername": "studywithlizzz",
  "authorName": "liz | studytok ...",
  "caption": "sometimes studying longer doesnt always mean higher grades...  #studytok #studytips",
  "hashtags": ["studytok", "studytips", "studyhacks", "studymotivation", "examtips"],
  "durationSeconds": 63,
  "createdAt": "2026-07-02T05:49:24.000Z",
  "language": "eng-US",
  "languageCode": "en",
  "languageName": "English",
  "isAutoGenerated": true,
  "isTranslated": false,
  "captionSource": "ASR",
  "text": "You scored at the top of your class because you studied for three hours the night before your exam, or so you thought...",
  "wordCount": 238,
  "characterCount": 1292,
  "segmentCount": 31,
  "segments": [{"start": 0, "end": 1.58, "startTime": "00:00:00.000", "endTime": "00:00:01.580", "text": "You scored at the top of your class"}],
  "srt": "1\n00:00:00,000 --> 00:00:01,580\nYou scored at the top of your class\n\n...",
  "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:01.580\nYou scored at the top of your class\n\n...",
  "availableLanguages": ["eng-US"],
  "playCount": 3600000,
  "likeCount": 455300,
  "commentCount": 1285,
  "shareCount": 21000,
  "musicTitle": "original sound",
  "scrapedAt": "2026-09-21T01:29:19.131Z"
}
```

| Field | How to read it |
|---|---|
| `text` | Every cue joined into one block, which is what you want for search or a model. |
| `segments` | Cue-level timings. `start` and `end` are seconds, `startTime` and `endTime` the timecode form. |
| `isAutoGenerated`, `captionSource` | Whether TikTok's own speech recognition made the track, or a person uploaded it. |
| `availableLanguages` | Every caption track that video exposed on that request, so you can see what else you could ask for. |
| `playCount`, `likeCount`, `commentCount`, `shareCount` | Counts at read time. A genuine zero comes back as `null`. |
| `coverUrl` | The video's cover image. The link carries an expiry. |

### 🧾 Reading the output

Three kinds of row can land in your dataset.

| Row | How to spot it | Billed |
|---|---|---|
| A transcript | `ok: true` and `recordType: "transcript"` | yes |
| The sample row | `_sample: true`, written only when the input was empty | no |
| A diagnostic | `ok: false`, `_diagnostic: true` and an `errorCode` | no |

Filter on `recordType == "transcript"` and you have your data. `charged: true` marks a real
transcript row and `false` marks a sample or diagnostic one. Read it as the row type: it is stamped
as the row is built, so it is not a receipt. Your run's own event count in Apify is the billing
record.

| Code | What it means |
|---|---|
| `NO_TRANSCRIPT` | The video has no caption track. Photo slideshows land here too. |
| `NOT_FOUND` | Deleted, private, region-locked, or shown only to a signed-in visitor. |
| `BAD_INPUT` | That line is not a TikTok video link or id. |
| `NOT_SERVED` | This transcript was not served this run. Re-run it later. Runs before 13 October 2026 wrote `BLOCKED` here. |
| `NETWORK` | The page was unreachable or answered badly. A share link whose redirect fails lands here. |
| `NO_RESULTS` | Too many videos in a row had no caption track, so the run stopped early instead of working through the list. |
| `TIME_BUDGET` | The run ran out of time before reaching that video. The run still ends as succeeded, with an amber status message, even when the time limit stopped it before any transcript came back. |
| `PROXY_INPUT_ADJUSTED` | Something you put in `proxyUrls` was unusable, so the run carried on without it. |
| `CHARGE_ERROR` | A charge could not be recorded. A couple in a row stops the run. |

### 💡 What people use it for

- Turning a set of videos into text you can search, quote or feed to a model.
- Making subtitle files for your own uploads, straight from `srt` or `vtt`.
- Finding which videos in a niche actually say a phrase, rather than just tagging it.
- Pulling the hook out of high-performing videos: the first few `segments` are the first few seconds.

From a hashtag to the hooks that work, in two runs:

1. Run [TikTok Hashtag Scraper](https://apify.com/dami_studio/tiktok-hashtag-scraper) on a tag in
   your niche and copy the `webVideoUrl` column.
2. Paste those links into **TikTok videos** here and keep the rows where `recordType` is
   `transcript`.
3. Sort by `playCount` and read the first two or three `segments` of the top videos.

### 🚧 What it does not do

- **It does not listen to audio.** No caption track means no transcript, and about one video in
  three has none.
- **Timings are cue-level, not word-level.** Each segment covers a phrase.
- **On-screen text is not included.** Stickers, overlays and burned-in captions are pictures, not a
  caption track.
- **Translations only exist where TikTok made one.** Asking for a language it does not hold gives
  you the original track, marked `isTranslated: false`.
- **No live videos or stories.**
- **Age-restricted and private videos** come back as uncharged
  `NOT_FOUND` rows.
- **A zero count reads as `null`.** A video with genuinely no comments shows `commentCount: null`.
- **If every line you paste is unusable**, you get the sample row rather than a message per line.
  Check your list if a run comes back with one row.
- **Counts are a snapshot**, and a popular video's play count moves while you read it.
- It is not an official TikTok tool. Dami's Studio is independent and is not affiliated with or endorsed by TikTok, or by any other company named on this page.

### 🧭 Which TikTok scraper do you need?

| If you want | Use |
|---|---|
| The spoken words of a video, as text, SRT and VTT | This one |
| Speech from a video file that has no caption track, with your own OpenAI key | [Video & Audio Transcriber](https://apify.com/dami_studio/video-audio-transcriber) |
| Comments under a video | [TikTok Comments Scraper](https://apify.com/dami_studio/tiktok-comments-scraper) |
| Videos posted under a hashtag | [TikTok Hashtag Scraper](https://apify.com/dami_studio/tiktok-hashtag-scraper) |
| A profile plus its newest videos, or a keyword search | [TikTok Scraper](https://apify.com/dami_studio/tiktok-scraper) |
| The same job on YouTube | [YouTube Transcript Scraper](https://apify.com/dami_studio/youtube-transcript-scraper) |

### ❓ Questions people ask

#### Do I need a TikTok account or an API key?

No. Videos are read with nothing signed in. The cookie field is optional.

#### Why did some TikTok videos come back with no transcript?

They have no caption track. TikTok makes one when it hears speech, so silent, music-only and some
slideshow posts have nothing to read.

#### Can I get a Spanish transcript of an English video?

Only if TikTok already holds a Spanish track for it. Nothing is translated here.

#### Can I feed it a whole profile or hashtag?

Not directly. Collect the video links first with one of the scrapers in the table above, then paste
them in.

#### Can I call it from code or connect it to an AI assistant?

The [API tab](https://apify.com/dami_studio/tiktok-transcript-scraper/api/python) has code for Python, JavaScript and
the CLI. MCP clients like Claude and ChatGPT use
`https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/tiktok-transcript-scraper`; coding assistants can load
[our skill file](https://api.apify.com/v2/key-value-stores/BTBHU3DdiuoF4JOsK/records/apify-tiktok-SKILL.md). All three
bill your Apify account at the same price.

#### Is it legal to scrape TikTok transcripts?

The captions are published with the public video. Copyright in the words belongs to whoever said
them. Apify's write-up on
[the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is a good starting
point, and we are not lawyers.

### 🆘 If something breaks

Open the **Issues** tab on the actor page. Send the video link and the run ID. The `errorCode` on the
diagnostic row usually names the problem on its own.

# Actor input Schema

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

The videos you want transcribed. A full link (https://www.tiktok.com/@user/video/7516208601434819862), a vm.tiktok.com or vt.tiktok.com share link, or just the bare numeric video id - all three work, and you can mix them in one list. Up to 1,000 per run.

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

How many transcripts to return at most. Keep it low while you are testing - you pay per transcript.

## `language` (type: `string`):

A language code such as es, fr, de or ja. When TikTok holds a translated caption track for the video you get that one and the row is marked isTranslated: true. When it does not, you get the original spoken track instead of an error. Leave empty for the original.

## `concurrency` (type: `integer`):

How many videos to read in parallel. Default 6, maximum 12. Lower it if you are working through a very long list and want to be gentle with the target.

## `sessionCookies` (type: `array`):

Optional: your own session, used only for your run. You are responsible for using it within the site's terms. Runs work without it.

## `proxyUrls` (type: `array`):

Leave this empty for a normal run. Fill it in only if you want the traffic to leave through proxy servers you already pay for, one URL per line, in the form http://user:pass@host:port.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@baobei55555j/video/7516208601434819862",
    "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766"
  ],
  "maxItems": 10,
  "language": "es"
}
```

# Actor output Schema

## `results` (type: `string`):

Every row in the default dataset: videoId, authorUsername, caption, durationSeconds, language, isAutoGenerated, isTranslated, segmentCount, wordCount, text, url, createdAt, playCount, inputUrl, authorName, authorUrl, hashtags, languageCode, languageName, captionSource, characterCount, segments, srt, vtt, availableLanguages, likeCount, commentCount, shareCount, musicTitle, coverUrl, scrapedAt. An empty, blocked or unmatched run returns a single uncharged row explaining what happened instead.

# 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/@baobei55555j/video/7516208601434819862",
        "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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/@baobei55555j/video/7516208601434819862",
        "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766",
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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/@baobei55555j/video/7516208601434819862",
    "https://www.tiktok.com/@studywithlizzz/video/7657803613355412766"
  ],
  "maxItems": 10
}' |
apify call dami_studio/tiktok-transcript-scraper --silent --output-dataset

```

## MCP server setup

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