# TikTok Transcript - Video Transcript, Captions & SRT (`scrapewise/tiktok-transcript`) Actor

Scrape the TikTok transcript of any video from its link, short link, share text or id: TikTok video transcript and subtitles as text, segments, SRT or VTT, in any language or translated to yours. Views and likes in the same row. No captions, private or restricted video = free.

- **URL**: https://apify.com/scrapewise/tiktok-transcript.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Videos, Social media, AI
- **Features:** Limited permissions
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.68 / 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: Video Transcript, Subtitles and Captions

Get the **TikTok transcript** of any public video from its link or id. This tool returns the **TikTok video transcript** and **TikTok subtitles** that TikTok itself generated, as plain text, timestamped segments, SRT or WebVTT, in the original language or translated.

Paste links such as `https://www.tiktok.com/@example/video/123` in bulk, with no limit per run, and get views and likes in the same row. Export to JSON, CSV or Excel for content research and AI pipelines.

### What it fixes

Problems people report with TikTok transcript tools, and what this Actor does about each one:

- **"The run failed and I got nothing."** One bad link never stops the run. Every input gets a row: the
  transcript, or a free row with an `errorCode` that says exactly why (no captions, private, deleted, restricted,
  invalid link). A blocked request is retried several times before it is reported.
- **"The transcript came back in English, but the video is in German."** With `language` empty you always get
  the language that is spoken in the video (TikTok's speech-to-text), never one of its machine translations.
  `originalLanguage` and `availableLanguages` show what TikTok has.
- **"I need it in English (or Spanish, or Japanese)."** `translateTo` translates the transcript, segments and
  SRT/VTT into any language: TikTok's own translation when it has one, machine translation otherwise. Same price.
- **"Short share links fail."** `vt.tiktok.com`, `vm.tiktok.com`, `tiktok.com/t/...`, embed and player links,
  links with tracking parameters, bare ids, and even the whole text the app copies when you tap Share all work.
- **"I can only send 10 videos at a time."** There is no limit per run. Paste hundreds of links, upload or link a
  text file with one link per line (`startUrls`), and set `maxItems` only if you want a cap.
- **"Transcript is null for a video posted today."** TikTok usually adds auto-captions within 24 to 48 hours of
  upload. The free `NO_CAPTIONS` row says how many hours ago the video was posted, so you know to run it again
  later instead of guessing.
- **"The caption and cover image are missing for music-only videos."** Turn on
  `includeMetadataWhenNoCaptions`: videos without speech still come back free, with the post caption, hashtags,
  date, duration, cover image and author handle.
- **"The thumbnail is a HEIC file my browser downloads instead of showing."** `coverUrl` is always an image
  browsers display (JPEG when TikTok's own cover would be HEIC).
- **"Export fails: the dataset does not have a schema."** The dataset has a schema and a ready table view; export
  to JSON, CSV, Excel or HTML works from the Output tab and the API.
- **"Payment required" errors from a third-party API.** Nothing here depends on another paid API: you pay only the
  per-transcript price below.

### At a glance

- **Price per 1,000 videos, Free plan:** US$ 0.80
- **Charged when the video has no captions:** No
- **Transcript as plain text:** Yes
- **Timestamped segments, SRT, VTT:** All three
- **Choose the language / every language / translate to any language:** Yes / Yes / Yes
- **Short links (vt.tiktok.com, vm.tiktok.com, tiktok.com/t/) and bare ids:** Yes
- **Views, likes, comments, shares, saves in the same row:** Yes
- **Music, hashtags, duration, author:** Yes
- **Videos per run:** No limit
- **Transcribes videos that have no TikTok captions:** No (see Limitations)

### One real row

From a cloud test run on 2026-09-28 (empty input, which uses a National Geographic video). `coverUrl` and the
long transcript are shortened here:

```json
{
  "id": "7549930445127896333",
  "url": "https://www.tiktok.com/@natgeo/video/7549930445127896333",
  "language": "en",
  "languageCode": "eng-US",
  "source": "ASR",
  "isAutoGenerated": true,
  "isMachineTranslated": false,
  "transcript": "Digging a hole to the other side of the world. Let me show you where you'll end up. [...] Where's your antipode? Let us know.",
  "wordCount": 251,
  "requestedLanguageFound": null,
  "availableLanguages": [{"language": "en", "languageCode": "eng-US", "source": "ASR"}],
  "caption": "Ever wondered where you'd end up if you started digging a hole through the Earth? [...]",
  "hashtags": [],
  "createTime": "2025-09-14T13:07:07Z",
  "timestamp": 1757855227,
  "durationSeconds": 74,
  "playCount": 1400000,
  "likeCount": 98900,
  "commentCount": 710,
  "shareCount": 2353,
  "saveCount": 13661,
  "repostCount": 0,
  "textLanguage": "en",
  "locationCreated": "BO",
  "isAd": false,
  "coverUrl": "https://p16-common-sign.tiktokcdn.com/...",
  "musicMeta": {"id": "7549930669510609677", "title": "original sound", "author": "National Geographic",
                "album": null, "isOriginalSound": true},
  "authorMeta": {"uniqueId": "natgeo", "nickname": "National Geographic", "verified": true,
                 "url": "https://www.tiktok.com/@natgeo", "followers": 9600000, "following": 62,
                 "totalLikes": 54800000, "videoCount": 1516},
  "sourceUrl": "https://www.tiktok.com/@natgeo/video/7549930445127896333",
  "scrapedAt": "2026-09-29T00:16:29Z",
  "error": null,
  "errorCode": null
}
```

With `includeSegments` each row adds `segments`: `[{"start": 0.46, "end": 2.3, "duration": 1.84, "text":
"Digging a hole to the other side of the world."}, ...]` (seconds). With `subtitleFormats` it adds `srt` and/or
`vtt` with the whole file. `source` is `ASR` (TikTok's speech-to-text in the spoken language) or `MT` (a machine
translation of it). With `translateTo` the row adds `translatedTo`, `translationSource` (`tiktok` or
`google_translate`) and `originalLanguage`. `locationCreated` is the country code TikTok records for the post.

### Input

Every field is optional. An empty input returns the transcripts of two public videos from the National Geographic
and BBC News accounts.

```json
{
  "videos": [
    "https://www.tiktok.com/@natgeo/video/7549930445127896333",
    "https://vt.tiktok.com/XXXXXXXXX/",
    "7652791912868482326"
  ],
  "language": "en",
  "includeSegments": true,
  "subtitleFormats": ["srt"]
}
```

| Field | What it does |
|---|---|
| `videos` | Video links (`tiktok.com/@handle/video/<id>`, also with `?lang=` and other parameters), photo post links, short share links (`vt.tiktok.com/...`, `vm.tiktok.com/...`, `tiktok.com/t/...`), embed and player links, numeric video ids, or the text the app copies when you tap Share. |
| `language` | Preferred language: `en`, `es`, `pt`, `pt-BR`, `fr`, `eng-US`... If the video has no caption in it, you get the original-language caption, then the first one available; `requestedLanguageFound` says which case happened. |
| `includeAllLanguages` | Adds `transcripts`: every caption TikTok has for the video (original and its translations), each with text and the segments or files you chose. |
| `includeSegments` | Adds `segments` with `start`, `end`, `duration` and `text`. |
| `subtitleFormats` | `srt` and/or `vtt`: adds ready-to-use subtitle files as text fields. |
| `translateTo` | Translate every transcript (text, segments, SRT/VTT) into this language: `en`, `es`, `de`, `ja`... |
| `maxItems` | Stop after this many transcripts (empty or 0 = no limit). |
| `includeMetadataWhenNoCaptions` | Free `NO_CAPTIONS` rows also carry the post caption, hashtags, date, duration, cover and author handle (no counts). |
| `startUrls` | Same as `videos`, in the Apify start URLs format; also accepts a link to a text file with one video link per line. |

### Switching from another TikTok transcript actor? Your existing input works

Paste the JSON you already send. These field names are read as follows:

| Your field | Read as |
|---|---|
| `videos`, `postURLs`, `postUrls`, `videoUrls`, `urls`, `startUrls`, `tiktokUrl`, `tiktokUrls`, `bulkUrls`, `videoIds` | Video links or ids (all merged, duplicates removed). `bulkUrls` and `startUrls` also accept a linked text file. |
| `language`, `languages`, `targetLanguage` | Preferred caption language. |
| `translateToEnglish: true` | Same as `translateTo: "en"`. |
| `downloadSubtitlesOptions` | `DOWNLOAD_SUBTITLES`: TikTok's captions, as always. The two transcription values are accepted: videos with TikTok captions get them, videos without come back as free `NO_CAPTIONS` rows (see Limitations). |
| `videoKvStoreIdOrName` | The VTT file of every caption is also saved in this key-value store, with its download link in `videoMeta.subtitleLinks[].downloadLink`. |
| `maxItems`, `maxResults`, `limit` | Maximum transcripts in the run. |
| `includeComments` | Accepted and ignored with a log line: TikTok only shows comments to signed-in sessions. |

The output keeps the names you already parse, on top of the fields shown above:

- Requests that use `postURLs` also get `text` (post caption), `webVideoUrl`, `submittedVideoUrl`,
  `createTimeISO`, `diggCount`, `collectCount`, `authorMeta.name`, `authorMeta.nickName`, `authorMeta.fans`,
  `authorMeta.heart`, `authorMeta.video` and `videoMeta.subtitleLinks` (`language`, `source`, `downloadLink` to the
  VTT saved in the run's key-value store, `tiktokLink`).
- Requests that use `tiktokUrl` or `bulkUrls` also get `videoId`, `tiktokUrl`, `videoDescription`, `viewsCount`,
  `likesCount`, `commentsCount`, `sharesCount`, `collectCount`, `videoDuration`, `musicTitle`, `musicAuthor`,
  `authorUsername`, `authorDisplayName`, `followerCount`, `coverImageUrl`, `srtSubtitles` and `vttSubtitles`.
- `transcript` is plain text, ready for an LLM. If your code expects the WebVTT text, add
  `"subtitleFormats": ["vtt"]` and read the `vtt` field.

### Price

- **US$ 0.80 per 1,000 transcripts** (US$ 0.0008 each). One charge per video, whatever the number of languages,
  segments, files or translations you ask for. No fee per run.
- Never charged: videos without captions, deleted, private, restricted or ad-only videos, invalid links, blocked
  requests and duplicates.
- Examples: 100 videos with captions = US$ 0.08. 10,000 = US$ 8.00.

You can set a maximum cost per run in Apify: the Actor stops when the limit is reached and keeps what it saved.

### Errors you may see

Every error is a row with `id`, `url`, `sourceUrl`, `error` and `errorCode`, and is never charged:

| errorCode | Meaning |
|---|---|
| `NO_CAPTIONS` | TikTok has no captions for this video: no speech (music-only clips are common), captions turned off, a photo post, or a video posted in the last day or two (the message says how many hours ago; run it again later). |
| `VIDEO_NOT_FOUND` | The video does not exist, was deleted, is an ad-only post, or the short link expired. |
| `PRIVATE_VIDEO` | The video is private. |
| `RESTRICTED_VIDEO` | TikTok shows this video only to signed-in users (age-restricted or sensitive content). |
| `INVALID_URL` | Not a TikTok video link or id (profile and search links are not supported). |
| `INVALID_INPUT` | A field has a wrong value (the message says which). |
| `BLOCKED` | TikTok did not answer after several attempts; run again. |
| `NOT_REACHED` | The run timeout arrived before this video. |

### Good to know

- In our tests 23 of 39 existing videos from brand and news accounts had captions (59%). Talking videos almost
  always have them; music, dance and silent clips usually do not. You pay only for the ones that do.
- 41 videos took 53 seconds in one cloud run.
- Proxy is included: you pay only the per-transcript price above.
- Public author data only: handle, display name, verified badge, followers, following, total likes and video
  count. The author's bio, email, phone and links to other networks are **never** collected, and any email
  address, phone number or WhatsApp/Telegram link written in a caption or spoken in a transcript is replaced by
  `[contact removed]`.

### Limitations

- **Only captions TikTok generated.** The Actor returns the captions TikTok itself created (auto-generated
  speech-to-text and its machine translations). It does not run its own speech recognition, so videos without
  TikTok captions come back as `NO_CAPTIONS` (free).
- **No search, no profiles, no hashtags.** Give it video links or ids; it does not list the videos of a profile,
  a hashtag or a keyword search.
- **No comments.** TikTok only shows comments to signed-in sessions.
- Auto-generated captions can misspell names and brands, exactly as they appear in the TikTok app.
- No video download (MP4).

### FAQ

**Do I need a TikTok account or cookies?** No. Everything comes from TikTok's public video pages.

**Which language will I get?** With `language` empty, the original spoken language. With `language` set, that
language if TikTok has it (often as a machine translation, `source: "MT"`), otherwise the original. With
`translateTo`, always the language you asked for. Turn on `includeAllLanguages` to get all of TikTok's captions in
one row.

**Can I use it from n8n, Make, Zapier or my own code?** Yes, like any Apify Actor: call it through the API with a
list of links and read the dataset in JSON, CSV or Excel. See "Switching from another TikTok transcript actor"
above for the field names it understands.

**How do I get the transcripts of all videos of a creator?** Collect the video links first (for example with a
TikTok profile scraper) and pass them in `videos`.

**Something broke or a field is missing?** Open an issue on the Actor page. Issues are answered within a day.

### Changelog

- **0.1 (8 Oct 2026):** `translateTo` (any language), `includeMetadataWhenNoCaptions`, `RESTRICTED_VIDEO`
  instead of `NO_CAPTIONS` for age-restricted videos, captions found on more videos, a hint for videos posted in the last 72 hours, browser-safe `coverUrl`, embed/player links
  and pasted share text, link list files, and the input and output field names of other TikTok transcript actors.
- **0.1 (28 Sep 2026):** first version. Video links, short links and ids; preferred language or all languages;
  plain text, segments, SRT and VTT; views, likes, comments, shares, saves, date, duration, music, hashtags and
  public author data in the same row; videos without captions are free.

# Actor input Schema

## `videos` (type: `array`):

TikTok videos, one per line: a video link (https://www.tiktok.com/@natgeo/video/7549930445127896333), a short share link (https://vt.tiktok.com/..., https://vm.tiktok.com/..., https://www.tiktok.com/t/...) or the numeric video id. Photo posts and links with ?lang= or other parameters also work. Each video returns one row with the full transcript text and the video stats. Profile and search links are not supported. Leave empty to run two example videos. Also accepts 'postUrls', 'videoUrls', 'urls', 'videoIds' or 'links'.

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

Language code of the transcript to return (for example en, es, pt, pt-BR, fr or eng-US). If the video has no caption in this language you get the original-language caption (auto-generated by TikTok), then the first one available; 'requestedLanguageFound' tells you which case happened. Empty means the original language. Also accepts 'targetLanguage' or 'languages'.

## `includeAllLanguages` (type: `boolean`):

Adds a 'transcripts' array with every caption TikTok has for the video (the original plus its machine translations), each with language, source, text and the segments or subtitle files chosen below. Same price per video. Off by default.

## `includeSegments` (type: `boolean`):

Adds a 'segments' array with start, end and duration in seconds and the text of each caption line, for quotes, chapters or syncing with the video. Same price. Off when the field is missing from the input.

## `subtitleFormats` (type: `array`):

Adds ready-to-use 'srt' and/or 'vtt' fields with the full subtitle file, to save as .srt or .vtt and upload to a video editor or player. Pick one, both or none. Same price. Also accepts 'formats'.

## `translateTo` (type: `string`):

Language code to translate every transcript into (for example en, es, de, fr or ja). TikTok's own translation is used when it has one; otherwise the transcript, segments and SRT/VTT are machine-translated. 'translatedTo' and 'translationSource' tell you which. Same price. Empty means no translation.

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

Stop after this many transcripts are delivered in the whole run (for example 100). Empty or 0 means no limit. You pay only per transcript delivered; videos without captions return free rows and do not count. Also accepts 'maxResults' or 'limit'.

## `includeMetadataWhenNoCaptions` (type: `boolean`):

Videos without captions always come back as free NO_CAPTIONS rows. When on, those rows also carry the post caption, hashtags, date, duration, cover image and author handle (no view, like or follower counts). Useful for recipe, product or music videos where the text is in the caption. Still free. Off by default.

## `postURLs` (type: `array`):

Same as 'TikTok videos', under the field name other TikTok transcript scrapers use, so you can switch without changing your integration. Merged with the list above. Rows requested this way also carry the field names those scrapers return (text, webVideoUrl, diggCount, videoMeta.subtitleLinks with a download link to each VTT file).

## `startUrls` (type: `array`):

Same as 'TikTok videos', in the Apify start URLs format: paste links, or link a text file with one video link per line (requestsFromUrl). Merged with the list above.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxy is the default and works for TikTok video pages. Failed requests are retried. Keep the default.

## Actor input object example

```json
{
  "videos": [
    "https://www.tiktok.com/@natgeo/video/7549930445127896333",
    "https://www.tiktok.com/@bbcnews/video/7652791912868482326"
  ],
  "includeSegments": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `resultsCsv` (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 = {
    "videos": [
        "https://www.tiktok.com/@natgeo/video/7549930445127896333",
        "https://www.tiktok.com/@bbcnews/video/7652791912868482326"
    ],
    "includeSegments": true,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/tiktok-transcript").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 = {
    "videos": [
        "https://www.tiktok.com/@natgeo/video/7549930445127896333",
        "https://www.tiktok.com/@bbcnews/video/7652791912868482326",
    ],
    "includeSegments": True,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/tiktok-transcript").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 '{
  "videos": [
    "https://www.tiktok.com/@natgeo/video/7549930445127896333",
    "https://www.tiktok.com/@bbcnews/video/7652791912868482326"
  ],
  "includeSegments": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/tiktok-transcript --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapewise/tiktok-transcript"
        }
    }
}
```

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/MzyQVwH8M2SXN7n1h/builds/e77obNLa5XqcAnopF/openapi.json
