# TikTok Transcript Scraper (`apimint/tiktok-transcript-scraper`) Actor

Get transcripts of all videos on a TikTok profile, or any list of TikTok links, in bulk. TikTok transcript API: TikTok captions or speech-to-text (transcriptSource says which), timestamped segments, text, language, hook, call to action, views, likes, shares, saves. Music-only videos free. No login.

- **URL**: https://apify.com/apimint/tiktok-transcript-scraper.md
- **Developed by:** [API Mint](https://apify.com/apimint) (community)
- **Categories:** AI, Social media, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 transcript (tiktok captions)s

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

Get transcripts of all videos on a TikTok profile, or of any list of TikTok links, in one run. It works as a TikTok transcript API too: call it from code, n8n, Make or an AI agent and get JSON back.

- **Bulk TikTok transcripts:** paste hundreds of video links, `vm.tiktok.com` short links, video IDs and profiles, mixed in one list.
- **TikTok profile transcripts:** a whole profile, newest first, with a date range if you want only recent videos.
- **TikTok captions or speech-to-text:** TikTok's own captions when the video has them (most talking videos do), speech-to-text when it doesn't. Each row says which (`transcriptSource`).
- **Every row:** the transcript with timestamps, the **hook** (the opening line), the **call to action**, the language, plus the caption, views, likes, comments, shares, saves, posting date and sound. Optional SRT or WebVTT subtitle files.

Music-only videos are detected and never charged. Every video without a transcript gets a row that says why, and is never charged. No TikTok account, no API key, no cookies.

| What you pay | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| Per 1,000 transcripts from TikTok's captions | $2.50 | $2.30 | $2.00 | $1.70 |
| Per 1,000 transcripts made by speech-to-text (first 3 minutes) | $15 | $14 | $12.50 | $10 |
| Per extra minute of a longer speech-to-text video | $0.005 | $0.005 | $0.005 | $0.005 |

Proxy traffic and speech-to-text are included. Music-only videos, photo posts, private or deleted videos and anything blocked are free.

Works with: [Instagram Reel Transcript Scraper](https://apify.com/apimint/instagram-reel-transcript-scraper) (the same row format for Reels) and [YouTube Transcript Scraper](https://apify.com/apimint/youtube-transcript-scraper) (channels, playlists and Shorts).

### What you get

| Field | Example |
|---|---|
| `text`, `wordCount` | the whole transcript as one string, 223 |
| `segments` | `[{start: 0.1, end: 1.46, text: "If a skincare brand told you"}, …]` |
| `hook`, `hookEndSeconds` | "If a skincare brand told you that they wanted content for their Instagram, would you know what to send them?", 4.42 |
| `cta`, `ctaType` | "Follow for more.", `follow` |
| `transcriptSource`, `captionType`, `language` | `tiktok-captions`, `auto`, `en` |
| `caption`, `hashtags`, `mentions` | the post caption and what's tagged in it |
| `views`, `likes`, `comments`, `shares`, `saves` | 9776, 839, 28, 27, 155 |
| `postedAt`, `durationSeconds`, `music` | 2026-10-08T…, 46, `{title: "original sound - GaryVee", isOriginalSound: true}` |
| `authorUsername`, `authorName`, `isAd`, `isAiGenerated` | garyvee, GaryVee, false, false |
| `srt`, `vtt` (optional) | subtitle files as text |
| `status`, `errorMessage` | `ok`, or why there is no transcript |

`hook` and `cta` are derived: the hook is what is said in the first seconds, completed to the end of the sentence; the call to action is the closing "comment…", "link in bio", "follow…", "DM me", "shop…" line found in the speech, else in the caption.

### How to get TikTok transcripts in bulk

#### Bulk TikTok transcripts from links

Paste video links into **Videos or profiles**, one per line: `tiktok.com/@user/video/…`, `vm.tiktok.com/…` or `vt.tiktok.com/…` short links (the ones TikTok's share button gives you), or bare video IDs.

#### TikTok profile transcripts

Paste a profile link (`https://www.tiktok.com/@washingtonpost`) or `@handle`. You get its newest videos first, up to **Max videos per profile** (0 = as many as TikTok lists). Add **Posted after** ("30 days", "2026-09-01") to keep only recent ones.

#### TikTok captions or speech-to-text

**Transcript source** decides. The default uses TikTok's captions when they exist (cheaper) and transcribes the rest from the audio. "Always speech-to-text" ignores TikTok's captions (useful when you want punctuation and our accuracy everywhere). "TikTok captions only" never transcribes: videos without captions get a free `no-captions` row. Every row's `transcriptSource` says which path it took, so you can see what you paid for.

#### Hooks and calls to action for competitor research

Run competitors' profiles and sort by `views`: the `hook` and `cta` columns show what top TikToks say first and what they ask viewers to do. The **Transcripts** view shows creator, hook, CTA and text side by side.

#### TikTok video to text for notes and AI

Turn off **Timestamped segments** to get plain text per video, ready for Notion, Obsidian, a summary prompt or a RAG index. Paste the share links straight from the app.

#### Subtitle files (SRT and WebVTT)

Pick SRT and/or WebVTT under **Subtitle files**. Each row then carries the transcript as subtitle text in `srt` or `vtt`, ready to save as a file.

#### Monitor profiles

Turn on **Only new videos** and run the Actor on a schedule (daily or weekly). Each run returns only videos it hasn't returned before for that profile, so you pay once per video. Send the results to Google Sheets, n8n, Make, Zapier or a webhook with Apify's integrations, and new transcripts arrive there on their own.

### TikTok transcript API

Call the Actor over HTTP and get the transcripts back as JSON in the same request. The request waits up to 5 minutes, which suits small jobs; for whole profiles, start a run and read its dataset when it finishes.

```bash
curl -X POST "https://api.apify.com/v2/acts/apimint~tiktok-transcript-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://www.tiktok.com/@garyvee/video/7693664152295869710", "https://www.tiktok.com/@washingtonpost"], "maxVideosPerProfile": 10}'
```

Apify's JavaScript and Python clients, the n8n and Make integrations and Apify's MCP server for AI agents all take the same input.

### Input example

```json
{
  "urls": [
    "https://www.tiktok.com/@garyvee/video/7693664152295869710",
    "https://vm.tiktok.com/ZN81NJUTF/",
    "https://www.tiktok.com/@washingtonpost"
  ],
  "maxVideosPerProfile": 30,
  "postedAfter": "30 days",
  "transcriptSource": "captions-first"
}
```

Switching from another TikTok Actor? Calls that use `startUrls`, `postURLs`, `videoUrls`, `videos`, `profiles`, `usernames` or `resultsPerPage` work as they are.

### Output example

```json
{
  "videoId": "7693664152295869710",
  "url": "https://www.tiktok.com/@garyvee/video/7693664152295869710",
  "status": "ok",
  "errorMessage": null,
  "transcriptSource": "tiktok-captions",
  "captionType": "auto",
  "language": "en",
  "text": "for everyone who's like wow wow wow and and all that and all cynical Elvis this is the key moment right now for everybody this is a good one I want everyone to call their most cynical negative parent aunt grandma whoever it is …",
  "wordCount": 114,
  "segments": [
    { "start": 0, "end": 4.12, "text": "for everyone who's like wow wow wow and and all that and all cynical" },
    { "start": 6.42, "end": 8.34, "text": "Elvis this is the key moment right now" }
  ],
  "hook": "for everyone who's like wow wow wow and and all that and all cynical",
  "hookEndSeconds": 4.12,
  "cta": null,
  "ctaType": null,
  "speechDetected": true,
  "caption": "Remember .. they can’t darken your light for too long … All of the dark is always temporary.. light 💡 🌞 always wins in the end !!!",
  "hashtags": [],
  "mentions": [],
  "postedAt": "2026-10-09T00:00:00.000Z",
  "durationSeconds": 41,
  "views": 8410,
  "likes": 380,
  "comments": 35,
  "shares": 12,
  "saves": 45,
  "music": { "title": "original sound - GaryVee", "author": "GaryVee", "isOriginalSound": true },
  "authorUsername": "garyvee",
  "authorName": "GaryVee",
  "authorUrl": "https://www.tiktok.com/@garyvee",
  "isAd": false,
  "isAiGenerated": false,
  "transcriptEngine": null,
  "extraMinutes": 0,
  "source": { "type": "video", "value": "https://www.tiktok.com/@garyvee/video/7693664152295869710" }
}
```

A video without a transcript:

```json
{ "videoId": "7692472349475622174", "status": "no-speech", "errorMessage": "No speech: music or sound only", "transcriptSource": null, "text": "" }
```

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

| Job | Free plan | Starter |
|---|---|---|
| 100 TikToks, TikTok captions only | $0.25 | $0.23 |
| 1,000 videos from profiles, captions first (about 3 in 4 talking videos have TikTok captions) | $5.40 | $5.00 |
| 100 TikToks, always speech-to-text (under 3 minutes each) | $1.50 | $1.40 |
| A 1,000-video profile, captions only | $2.50 | $2.30 |

Set **Max transcripts in total** or a maximum cost per run in the run options, and the Actor stops cleanly when it's reached.

### Status codes (none of them is charged)

| Status | Meaning |
|---|---|
| `no-speech` | Music or sound only, nothing spoken |
| `no-captions` | TikTok has no captions and you chose "captions only" |
| `no-audio` | The video has no sound track |
| `too-long` | Needs speech-to-text and is longer than **Skip videos longer than (minutes)** |
| `not-a-video` | A photo post |
| `private` | Private video or private account |
| `unavailable` | Deleted or not available |
| `blocked` | TikTok kept refusing it on fresh IPs (rare; try again later) |
| `error` | Something else went wrong; `errorMessage` says what |

### What TikTok doesn't give without a login

- Private or friends-only videos, liked or saved videos, Stories, DMs.
- Hashtag and keyword search (they need signed requests). Paste the video links instead.
- Text written on the video, speaker names, word-by-word timing.
- Translations: the transcript is in the language spoken.

### FAQ

**Is it legal to scrape TikTok transcripts?** The Actor reads public TikToks the way a logged-out visitor sees them and returns text for analysis. What a creator says is their work: use transcripts for research and analysis, not to republish.

**Why not the official TikTok API?** TikTok's Research API is the only one with a speech-to-text field, and it is open to academic institutions only. The Display API has no transcript or caption field and lists only the videos of users who authorised your app. This Actor reads the public caption track every visitor gets, and transcribes the audio when there is none.

**How accurate is it?** TikTok's own captions are TikTok's speech recognition, usually without punctuation fixes. Our speech-to-text on paid plans is OpenAI's, with the caption's names (brands, products, @handles) used as spelling hints. On the Free plan it's an open-source Whisper model on the run's own computer: free for everyone, a little less accurate and slower (give the run 4 GB of memory for the best speed).

**Which languages?** The transcript is in the language spoken; it is never translated. Set **Language hint** to pick TikTok's caption track in another language when TikTok has one.

**What if TikTok blocks the run?** A few blocked requests are normal and retried on fresh IPs. If TikTok starts blocking most of them, the run stops early and tells you so, instead of grinding on. Blocked videos are never charged; try again later.

**Can I use it from n8n, Make, Zapier, an API or an AI agent?** Yes. Use the Apify integration or API with the input above (see "TikTok transcript API"), or connect it to an AI agent through Apify's MCP server.

**How often should I run it?** For a profile you follow, weekly with **Only new videos** on is enough for most creators; daily for news accounts. Results can go straight to Google Sheets or an n8n workflow.

**How is it different from other TikTok transcript scrapers?**

| | This Actor | Typical |
|---|---|---|
| Profiles and video links in one run | Yes | URLs only, one per run |
| TikTok captions first, speech-to-text only when needed | Yes, and the row says which | Captions only, or AI on every video |
| Hook and call to action | Yes | No |
| Music-only videos | Detected, free | Charged, empty transcript |
| Reason for every missing transcript | Yes, free row | Empty result or failed run |
| Timestamps inline | Yes | Often in a side file |
| Only new videos for schedules | Yes | Rare |

### Related Actors

- [Instagram Reel Transcript Scraper](https://apify.com/apimint/instagram-reel-transcript-scraper): the same transcript, hook and call-to-action row for Instagram Reels.
- [YouTube Transcript Scraper](https://apify.com/apimint/youtube-transcript-scraper): transcripts of whole YouTube channels, playlists and Shorts.
- [TikTok Scraper](https://apify.com/clockworks/tiktok-scraper): hashtag and search results whose video links you can feed into this Actor.
- [TikTok Comments Scraper](https://apify.com/clockworks/tiktok-comments-scraper): the comments under each video.
- [Website Content Crawler](https://apify.com/apify/website-content-crawler): web pages as text, to sit next to transcripts in a RAG index.

### Feedback

Found a video that should work but doesn't? Open an issue with the video URL and we'll look at it. Reviews help other people find the Actor. See the [changelog](./CHANGELOG.md) for updates.

# Changelog

This Actor's version history is a separate document: https://apify.com/apimint/tiktok-transcript-scraper/changelog.md

# Actor input Schema

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

One per line, mixed freely: video URLs (tiktok.com/@user/video/…), vm.tiktok.com short links, video IDs, profile URLs or @handles. A profile gives its newest videos.

## `maxVideosPerProfile` (type: `integer`):

Newest first. 0 = as many as TikTok lists.

## `postedAfter` (type: `string`):

Profiles only. A date (2026-09-01) or a period back from today ("30 days"). Inclusive.

## `postedBefore` (type: `string`):

Profiles only. Same format as "Posted after". Inclusive.

## `maxVideos` (type: `integer`):

Stop after this many charged transcripts across all sources. 0 = no limit (the run's maximum charge still applies).

## `transcriptSource` (type: `string`):

TikTok has its own captions for most talking videos: they are cheaper (transcript event). Videos without them are transcribed from the audio (transcript-ai event). "Always speech-to-text" ignores TikTok's captions; "captions only" never transcribes (videos without captions get a free no-captions row).

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

Optional two-letter code ("en", "es"). Picks TikTok's caption track in that language when there is one (including TikTok's translations), and hints speech-to-text. Leave empty for the language spoken.

## `maxDurationMinutes` (type: `integer`):

Videos longer than this that would need speech-to-text get a free "too-long" row. 0 = no limit.

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

The transcript in timed pieces (field segments), cut at pauses.

## `extraFormats` (type: `array`):

Add the transcript as SRT and/or WebVTT text in each row.

## `includeFailures` (type: `boolean`):

Add a free row with a status (no-speech, no-captions, too-long, not-a-video, private, unavailable, blocked) for every video without a transcript. Never charged.

## `onlyNewVideos` (type: `boolean`):

For profiles: skip videos this Actor already returned for the same profile in your earlier runs. Use with a schedule to get each new video once. Skipped videos are not charged.

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

Apify datacenter proxy by default; proxy traffic is included in the price. If TikTok blocks it, the Actor switches to residential by itself.

## Actor input object example

```json
{
  "urls": [
    "https://www.tiktok.com/@garyvee/video/7693664152295869710",
    "https://www.tiktok.com/@washingtonpost"
  ],
  "maxVideosPerProfile": 3,
  "maxVideos": 0,
  "transcriptSource": "captions-first",
  "maxDurationMinutes": 10,
  "includeSegments": true,
  "extraFormats": [],
  "includeFailures": true,
  "onlyNewVideos": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per video: transcript, segments, hook, call to action and video details, or the reason there is none.

## `summary` (type: `string`):

Per source: videos listed, transcripts by source, rows without a transcript by status, blocks, timings, and why the run stopped.

# 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.tiktok.com/@garyvee/video/7693664152295869710",
        "https://www.tiktok.com/@washingtonpost"
    ],
    "maxVideosPerProfile": 3,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apimint/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 = {
    "urls": [
        "https://www.tiktok.com/@garyvee/video/7693664152295869710",
        "https://www.tiktok.com/@washingtonpost",
    ],
    "maxVideosPerProfile": 3,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apimint/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 '{
  "urls": [
    "https://www.tiktok.com/@garyvee/video/7693664152295869710",
    "https://www.tiktok.com/@washingtonpost"
  ],
  "maxVideosPerProfile": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apimint/tiktok-transcript-scraper --silent --output-dataset

```

## MCP server setup

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