How to use it: 3 steps
- Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
- Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example:
https://www.tiktok.com/@apifytech/video/7398101551744552225in TikTok video links. Each start is one run. - Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
What it does
Get the transcript of any public TikTok video: timestamped text from TikTok captions, or speech-to-text when a video has no captions. No TikTok login, no cookies.
- the full transcript as plain text;
- segments with start and end times in seconds;
- chunks of about 1,000 characters with times, ready for AI tools;
- metadata: author, description, hashtags, date, duration, views, likes, comments, shares, saves and sound;
- a clear status and reason when a video has no text (photo post, library sound only, silence, deleted video and more).
Good for
- Repurpose TikTok videos into blog posts, captions, newsletters or scripts.
- Feed video text to ChatGPT, Claude or a RAG pipeline for summaries and research.
- Track what creators or competitors say in their newest videos, on a schedule.
Who uses it
Content creators
Turn TikTok videos into blog posts, captions or scripts.
AI and data teams
Feed video text to ChatGPT, Claude or a RAG pipeline.
Brand and market researchers
Track what creators say in their newest videos.
Price
Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.
| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.0025 | Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more. |
| Video | $0.0009 (from $0.00063 on paid Apify plans) | One TikTok video found and saved with its metadata and transcript (or the reason there is no text). Not charged for invalid links, videos not found, or videos skipped as already processed. |
| Speech-to-text, 10 seconds | $0.002 (from $0.0014 on paid Apify plans) | Each started 10 seconds of audio run through speech-to-text (also when it finds no speech), only for videos without usable TikTok captions and only when fallbackToSpeechToText or translateToEnglish needs it. |
| Video checked, no paid row | $0.0001 | TikTok was checked but there is no paid row: a video not found, a profile not found, private or without videos, or a profile video skipped by skipProcessed after TikTok listed it. Invalid links and blocked requests are not charged. |
Examples
- One result: about $0.0034.
- 1,000 results: about $0.90.
- Every day 100 results, for 30 days: about $2.77 a month.
Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 5,500 results.
Prices checked on 8 November 2026. See the current price on Apify.
Questions
Do I need a TikTok account or cookies?
No. The tool reads public pages, without login or cookies.
Can I get the text in another language?
Set language to use TikTok captions in that language. Set translateToEnglish to get English text.
What if a video has no captions?
The tool listens to the audio and writes the text with Whisper. You can turn this off.
Why is speech-to-text charged when the result is NO_SPEECH?
Speech-to-text has to process the whole audio to learn that it is only music or noise. That work is charged per 10 seconds. Videos that clearly have no speech (library sound only, silent, photo posts) are not sent to speech-to-text.
Is the transcript complete and correct?
It is as good as TikTok's captions or the Whisper base model. TikTok's own speech recognition and Whisper can mishear names and words. confidence and captionType show where the text came from.
Details
Step by step on Apify
- Open the Input tab. The field TikTok video links already has one example video (box 1 in the picture).
- Replace it with your own links, one per line. You can also add usernames in Profiles.
- Keep Transcript options as they are (box 3): captions first, speech-to-text when there are none.
- Click Start.
- When the run ends, open the Output tab. The Overview table shows the status, where the text came from and the transcript (box 5).
Use cases
| Task | Input | You get | Key fields | Next step |
|---|---|---|---|---|
| Turn a video into a blog post or script | videoUrls | One row per video | transcript, description, hashtags | Copy to a doc, or send to an LLM |
| Give an AI tool clean video text | videoUrls | Row with chunks | chunks (text, start, end), videoUrl | RAG / vector database, MCP agent |
| Make subtitles | videoUrls + saveSubtitleFiles | SRT / VTT / TXT files | files.srt, files.vtt | Video editor |
| Watch what creators say | profiles + skipProcessed | Rows for new videos only | transcript, createTimeISO, stats | Schedule, Slack or Notion summary |
| Research topics or trends | profiles or videoUrls | Rows with metadata | transcript, hashtags, stats.playCount | CSV / Excel |
Tips for better results
- Add video links, or a profile name to take its newest videos. One run takes up to 1,000 videos.
- A video with only a library sound has no speech. It gets NO_ORIGINAL_AUDIO and no text.
- Whisper base works best on clear speech. Check the confidence field.
Limits and good to know
- Only public videos and public profiles. Private accounts and private videos return
PRIVATE_ACCOUNTornot_found. No login is used, so the Actor cannot see what only followers see - Up to 1,000 links and 50 profiles (up to 500 newest videos each) per run, but at most 1,000 videos in total per run (links and profile videos together). Profiles after that limit get a row with
RUN_VIDEO_LIMIT; a profile not reached before the run timeout getsRUN_TIME_LIMIT. Split bigger jobs into several runs - Speech-to-text works on one video at a time: about 1 hour of audio takes about 22 minutes of run time. The default run timeout is 1 hour, which fits about 2.5 hours of audio. For more, raise the timeout or split the input
- Speech-to-text uses the Whisper base model. It is good for clear speech; songs, strong accents and noise give weaker text (look at
confidence) - A video with only a sound from the TikTok library (a song, a popular sound) has no original speech: it gets
NO_ORIGINAL_AUDIOand no text - Short links (
vm.tiktok.com/…,tiktok.com/t/…) are supported; a short link that no longer leads to a video getsNOT_FOUND. We checked the expired case live; a working short link was checked only in tests - The output fields are our own. They are not the same as other TikTok transcript Actors, so a switch may need small changes in your code
- Comments, video files and downloads are not part of the output. The video is not stored
Troubleshooting
errorCode | Meaning |
|---|---|
NO_CAPTIONS | TikTok has no captions and fallbackToSpeechToText is off |
NO_ORIGINAL_AUDIO | Only a TikTok library sound, no original speech |
NO_SPEECH | Silent video, or only music or noise |
NO_AUDIO | The video file has no sound |
PHOTO_POST | Photo slideshow, no spoken audio |
TOO_LONG | Longer than maxSpeechMinutesPerVideo |
CHARGE_LIMIT | Your maximum cost per run left no room for speech-to-text |
RUN_TIME_LIMIT | The run reached its timeout first |
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.
{
"videoUrl": "https://www.tiktok.com/@apifytech/video/7698373675267001622",
"videoId": "7698373675267001622",
"status": "complete",
"source": "captions",
"captionType": "tiktok-asr",
"confidence": 0.85,
"language": "en",
"transcript": "If I just makes it super easy to unlock that, because going to try and get a Google Maps API …",
"segments": [
{"start": 0.1, "end": 2.78, "text": "If I just makes it super easy to unlock that,"},
{"start": 2.781, "end": 3.581, "text": "because"}
],
"wordCount": 155,
"noTranscriptReason": null,
"errorCode": null,
"hashtags": ["apify", "aiagents", "vibecoding", "mcp"],
"createTimeISO": "2026-10-21T14:00:00Z",
"durationSeconds": 57,
"author": {"username": "apifytech", "nickname": "Apify", "verified": false, "followerCount": 3589},
"stats": {"playCount": 783, "diggCount": 5, "commentCount": 0, "shareCount": 1, "collectCount": 4},
"music": {"title": "original sound - Apify", "author": "Apify", "isOriginal": true},
"files": null,
"speechSecondsCharged": 0
}Use it from code
Actor ID: cliqtomedia/tiktok-transcript. You need your Apify API token from Apify Console → Settings → API & Integrations.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/tiktok-transcript").call(run_input={
"videoUrls": [
"https://www.tiktok.com/@apifytech/video/7398101551744552225"
],
"maxVideosPerProfile": 10
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~tiktok-transcript/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"videoUrls": ["https://www.tiktok.com/@apifytech/video/7398101551744552225"], "maxVideosPerProfile": 10}'# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("cliqtomedia/tiktok-transcript")
result = tool.invoke({"run_input": {"videoUrls": ["https://www.tiktok.com/@apifytech/video/7398101551744552225"], "maxVideosPerProfile": 10}})
print(result)The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.
Data fields (28)
| Field | Type | Meaning |
|---|---|---|
videoUrl | string | TikTok link of the video. |
inputUrl | string | The link or name as given in the input (or the profile listing link). |
videoId | string | TikTok video ID. |
status | string | complete (transcript found), partial (video found, no text: see noTranscriptReason), not_found (removed, private or not available) or error (see errorCode). |
source | string | Where the text came from: captions (TikTok's own captions), whisper (speech-to-text) or none. |
captionType | string | tiktok-creator, tiktok-asr (TikTok's automatic captions), tiktok-translation or whisper-base. |
confidence | number | 0–1. TikTok captions have fixed levels (creator 0.95, automatic 0.85, translation 0.75); speech-to-text gets Whisper's own score. |
language | string | Language code of the transcript. |
availableCaptionLanguages | array | Caption languages TikTok has for this video. |
transcript | string | Plain text of the transcript. |
segments | array | Transcript lines with start and end in seconds. |
chunks | array | Pieces of about chunkCharacters characters with index, start, end and text, for AI tools. |
wordCount | integer | Words in the transcript. |
noTranscriptReason | string | Why there is no (full) text, in plain words. |
errorCode | string | Stable code of the reason: NO_ORIGINAL_AUDIO, NO_CAPTIONS, NO_SPEECH, TOO_LONG, PHOTO_POST, NOT_FOUND, NO_VIDEOS, PRIVATE_ACCOUNT, INVALID_URL, BLOCKED, CHARGE_LIMIT, … |
description | string | Video caption text written by the author. |
hashtags | array | Hashtags of the video. |
createTimeISO | string | When the video was posted (UTC). |
durationSeconds | integer | Video length in seconds. |
descriptionLanguage | string | Language of the description, as TikTok detects it. |
isPhotoPost | boolean | true for photo posts (slideshows). |
author | object | username, nickname, id, verified, followerCount (outputFormat nested). |
stats | object | playCount, diggCount, commentCount, shareCount, collectCount (outputFormat nested). |
music | object | title, author, isOriginal of the sound (outputFormat nested). |
files | object | Links to srt, vtt and txt files when saveSubtitleFiles is on (outputFormat nested). |
speechSecondsCharged | integer | Seconds of audio charged for speech-to-text (in 10-second steps). |
profile | string | Profile the video was listed from. |
fetchedAt | string | When the row was made (UTC). |
Input settings (15)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| TikTok video links | videoUrls | array | ["https://www.tiktok.com/@apifytech/video/7398101551744552225"] |
| Profiles (newest videos) | profiles | array | |
| Videos per profile | maxVideosPerProfile | integer | 10 |
| Caption language | language | string | "" |
| Speech-to-text when there are no captions | fallbackToSpeechToText | boolean | true |
| English transcript | translateToEnglish | boolean | false |
| Max speech-to-text minutes per video | maxSpeechMinutesPerVideo | integer | 10 |
| Chunk size for AI (characters) | chunkCharacters | integer | 1000 |
| Save SRT, VTT and TXT files | saveSubtitleFiles | boolean | false |
| Output format | outputFormat | string | "nested" |
| Skip videos processed in earlier runs | skipProcessed | boolean | false |
| State name | stateName | string | "tiktok-transcript-state" |
| Proxy | proxyConfiguration | object | |
| Send results to (optional) | deliveryConnector | string | |
| Notion page or channel (optional) | deliveryTarget | string |