TikTok Transcript Scraper: Captions & Speech to Text
Pricing
from $0.63 / 1,000 videos
TikTok Transcript Scraper: Captions & Speech to Text
Get TikTok transcripts in bulk, no login: captions with timestamps, speech-to-text when a video has none, a profile's newest videos, SRT/VTT files and metadata. Repurpose videos, feed AI tools, research trends.
Pricing
from $0.63 / 1,000 videos
Rating
0.0
(0)
Developer
Cliqto Media
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Security
Limited permissionsShare
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.
Paste one or more TikTok video links (or a profile name) and get one row per video with clean text, segments with start and end times, AI-ready chunks and video metadata. The smallest run is one video link and takes a few seconds.

Table of contents
- What it does
- How it works
- Quick start
- Use cases
- Input
- Output
- Pricing
- Limits
- API, export and integrations
- Troubleshooting
- FAQ
- Related Actors
- Support
What it does
The Actor turns public TikTok videos into text. For each video it returns:
- 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).
Text comes from TikTok's own captions when the video has them. When it has none, the Actor listens to the audio and writes the text with Whisper speech-to-text (you can turn this off). It also can take the newest videos of a public profile and save SRT, VTT and TXT files.
Good fit
- 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.
How it works
- The Actor opens the public page of each TikTok video, the same page anyone can see without an account. For a profile, it reads the list of its newest public videos.
- If TikTok has captions for the video (written by the creator, made by TikTok's speech recognition, or TikTok's translation), the Actor uses them. Otherwise it downloads the audio for a moment and turns the speech into text. The video is not stored.
- It saves one row per video in the dataset, with a status for every input link, and a short run summary (
RUN_SUMMARY) in the key-value store.
Quick start
-
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).
Expected result: one row with status complete, source captions and about 100 words of English text with 12 timed segments.
Use cases
| Buyer job | Input path | Output entity | Key fields | Next integration |
|---|---|---|---|---|
| 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 |
Input
Input fields
| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
|---|---|---|---|---|---|---|---|---|
videoUrls | TikTok video links | list of text | one of videoUrls / profiles | prefill: one example video | up to 1,000; video, short, photo and profile links, or video IDs | Which videos to transcribe | https://www.tiktok.com/@apifytech/video/7398101551744552225 | Main input |
profiles | Profiles | list of text | one of videoUrls / profiles | empty | up to 50 usernames or profile links | Takes the newest videos of each profile | @apifytech | For monitoring creators |
maxVideosPerProfile | Videos per profile | number | no | 10 | 1โ500 | How many newest videos per profile | 20 | Keep low for a first test |
language | Caption language | text | no | empty (original language) | two-letter code | Uses TikTok captions in this language when they exist | es | Leave empty for the spoken language |
fallbackToSpeechToText | Speech-to-text when no captions | yes/no | no | yes | yes / no | Transcribes audio of videos without captions | false | Turn off for the cheapest, fastest run |
translateToEnglish | Translate to English | yes/no | no | no | yes / no | English captions, or Whisper translates the speech | true | When you need English for every video |
maxSpeechMinutesPerVideo | Max speech minutes per video | number | no | 10 | 1โ60 | Longer videos without captions get no text and no speech charge | 5 | Protects your budget |
chunkCharacters | Chunk size | number | no | 1000 | 0โ10,000 (0 = no chunks) | Size of AI-ready chunks | 2000 | Match your AI tool's context |
saveSubtitleFiles | Save subtitle files | yes/no | no | no | yes / no | Saves SRT, VTT and TXT files, links in files | true | For video editors |
outputFormat | Output format | choice | no | nested | nested, flat | flat makes columns like authorUsername, playCount | flat | flat for CSV / Excel |
skipProcessed | Skip videos from earlier runs | yes/no | no | no | yes / no | Skips videos already returned ($0.0001 each instead of a full row) | true | For scheduled runs |
stateName | State name | text | no | tiktok-transcript-state | letters, digits, - | Store that remembers returned videos | brand-watch | One name per monitoring task |
proxyConfiguration | Proxy | proxy | no | none | Apify Proxy or your own | Direct by default; switches to Apify Proxy by itself if TikTok refuses | โ | Usually leave empty |
deliveryConnector | Send summary to | connector | no | none | your Slack, Notion or other MCP connector | Posts a short summary after the run | โ | Optional |
deliveryTarget | Where to post | text | no | empty | Notion page link or Slack channel ID | Target page or channel | โ | Optional |
Give at least one link or profile; an empty input stops with a clear message. The same video given twice (for example with and without ?is_from_webapp=1) is processed once. Text that is not a TikTok link gets its own row with errorCode INVALID_URL. A profile link in videoUrls works like a profiles entry.
Interacting settings
| When | Input A | Input B | Effective behavior | Example | Cost/result effect |
|---|---|---|---|---|---|
| A video has captions in several languages | language | translateToEnglish | translateToEnglish wins: English captions first, else Whisper translates | language: es, translateToEnglish: true | Whisper translation is charged like speech-to-text |
| A video has no captions | fallbackToSpeechToText | maxSpeechMinutesPerVideo | Transcribed only when on and the video is not longer than the limit | 15-minute video, limit 10 | No text (TOO_LONG), no speech charge |
| Scheduled monitoring | skipProcessed | stateName | Videos returned before under the same name are skipped | daily run of @brand | Skipped videos cost $0.0001 each (video-checked) |
| You set a maximum cost per run | Apify run option | fallbackToSpeechToText | Speech-to-text stops when the next unit does not fit; the last text may be cut (TRUNCATED) | max $0.05 | You never pay more than you set |
Input examples
One video
{"videoUrls": ["https://www.tiktok.com/@apifytech/video/7398101551744552225"]}
Expected behavior: reads TikTok's captions of the video.
Expected output: one row, status complete, source captions, transcript, 12 segments.
Limit or cost note: the start fee ($0.005 at the default 2048 MB) and one video event, no speech charge.
Newest videos of creators, captions only
{"profiles": ["@apifytech"],"maxVideosPerProfile": 20,"fallbackToSpeechToText": false,"outputFormat": "flat"}
Expected behavior: takes the 20 newest videos and uses only TikTok captions.
Expected output: 20 rows; videos without captions have errorCode NO_CAPTIONS.
Limit or cost note: only video events and a $0.0025 start fee, because the run uses 1 GB of memory; it is fast.
Output
Output fields
| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
|---|---|---|---|---|---|
videoUrl | Full link of the video | text | no | https://www.tiktok.com/@apifytech/video/7398101551744552225 | Built from the author and video ID |
inputUrl | The link as you gave it | text | no | https://vm.tiktok.com/โฆ | Your input |
videoId | TikTok video ID | text | when the link is invalid | 7398101551744552225 | |
status | Result of this row | text | no | complete, partial, not_found, error | partial = video found, no or cut text |
source | Where the text came from | text | no | captions, whisper, none | |
captionType | Kind of text | text | yes | tiktok-creator, tiktok-asr, tiktok-translation, whisper-base | |
confidence | How sure the text is, 0โ1 | number | yes | 0.85 | Fixed for TikTok captions (creator 0.95, TikTok speech recognition 0.85, translation 0.75); measured for Whisper |
language | Language of the text | text | yes | en | |
availableCaptionLanguages | Caption languages TikTok has | list | can be [] | ["en", "es"] | |
transcript | Full text | text | yes | Are you doing research in HR or โฆ | |
segments | Timed lines | list of {start, end, text} | can be [] | {"start": 0.02, "end": 1.42, "text": "Are you doing research in HR"} | Seconds |
chunks | AI-ready pieces | list of {index, start, end, text} | can be [] | Size from chunkCharacters | |
wordCount | Words in the transcript | number | 0 when no text | 96 | |
noTranscriptReason | Why there is no or only part of the text | text | yes | The video uses only a sound from the TikTok library โฆ | Plain English |
errorCode | Short code of the reason | text | yes | see Troubleshooting | |
description, hashtags | Video caption text and hashtags | text, list | yes | #webscraping | |
createTimeISO, durationSeconds | Upload time (UTC) and length | text, number | yes | 2024-07-31TโฆZ, 23 | |
isPhotoPost | Photo post (slideshow) | yes/no | yes | false | |
author | username, nickname, id, verified, followerCount | group | yes | apifytech | Flat: authorUsername โฆ |
stats | playCount, diggCount (likes), commentCount, shareCount, collectCount (saves) | group | yes | 783 | Flat: playCount โฆ |
music | Sound title, author, isOriginal | group | yes | original sound - Apify | Flat: musicTitle โฆ |
files | Links to srt, vtt, txt files | group | yes | Only with saveSubtitleFiles | |
speechSecondsCharged | Seconds of audio charged for speech-to-text | number | 0 | 60 | Rounded up to 10 s |
profile | Profile this video came from | text | yes | apifytech | |
fetchedAt | When the row was made (UTC) | text | yes | 2026-11-01T07:40:07Z |
Output entities and surfaces
| Situation | Dataset/API/KVS/live view | Result shape | User action |
|---|---|---|---|
| Normal item | Dataset, views Overview and Transcripts with timestamps | status complete, text and metadata | Open, export or use transcript / segments |
| Video has no speech | Dataset | status partial, metadata, errorCode + noTranscriptReason | Read the reason; nothing to retry |
| Deleted or private video, bad link | Dataset | status not_found or error, errorCode | Check the link |
| Technical failure or retry | Dataset + RUN_SUMMARY in the key-value store | errorCode BLOCKED / SKIPPED_BLOCKED; summary reason SOURCE_ERROR | Run again later with the same input |
| Subtitle files | Key-value store, transcript-<videoId>.srt / .vtt / .txt | Files, links in files | Download or link |
Output example
{"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}
This example is trimmed: it shows 2 of the segments and leaves out chunks and a few fields. null means the value does not apply (no error, no files asked). Text from TikTok's speech recognition or from Whisper can have small mistakes, like "If I" in place of "Apify" above.
Send results to Slack or Notion
Pick your connector in the optional deliveryConnector field. After the run saves its data, the Actor posts a short summary (up to 25 rows and a link to the full dataset) there. Put a Notion page link or a Slack channel ID in deliveryTarget: in Notion every run is added on top of that one page, so your workspace does not fill up with new pages. A delivery error never fails the run and costs nothing extra. Connect a service once in Apify Console โ MCP connectors.
Pricing
Pricing unit
You pay per event. Apify platform usage (compute, proxy, storage) is included: the developer pays it.
| Event | When it is charged | FREE | BRONZE | SILVER | GOLD and higher |
|---|---|---|---|---|---|
apify-actor-start | Once per run, one event per GB of run memory (minimum one) | $0.0025 | $0.0025 | $0.0025 | $0.0025 |
video | A video was found and its row has metadata, with or without text | $0.0009 | $0.00081 | $0.00072 | $0.00063 |
speech-10-seconds | Each started 10 seconds of audio sent to speech-to-text | $0.002 | $0.0018 | $0.0016 | $0.0014 |
video-checked | TikTok was checked but there is no paid row: a video not found, a profile not found, private or without videos, a video skipped by skipProcessed after TikTok listed it | $0.0001 | $0.0001 | $0.0001 | $0.0001 |
- The start fee grows with memory: $0.005 at the default 2048 MB, $0.0025 at 1024 MB (the Actor picks 1024 MB itself when
fallbackToSpeechToTextis off andtranslateToEnglishis off), $0.01 if you raise memory to 4096 MB. It covers starting the run, so a run that finds nothing is not free. - Videos with TikTok captions cost the
videoevent: $0.90 per 1,000 videos on the FREE plan, plus one start fee per run. Put many videos in one run to share it. - Speech-to-text is charged for the audio it processed, also when the result is
NO_SPEECH(music or noise). One minute of audio is 6 units: $0.012 on FREE. - A found video without text (photo post, library sound only, silent video,
NO_CAPTIONS,TOO_LONG) is charged as onevideoevent, because you get its metadata and the reason. Speech-to-text is not started for these, so there is no speech charge. - A deleted or private video, a profile that is not found, private or empty, and a profile video skipped by
skipProcessedcost onevideo-checkedevent ($0.0001): TikTok still has to be asked. That is $0.10 per 1,000. - Invalid links, blocked requests (
SKIPPED_BLOCKED) and links skipped byskipProcessedbefore any request cost nothing. - A run where nothing is found costs only the start fee ($0.005 at 2048 MB). A run where every link is invalid ends as Failed and also pays the start fee, because the run was started.
- If TikTok refuses 3 videos in a row on every route, or stops answering for over 45 seconds, the Actor stops sending requests: the remaining rows are
SKIPPED_BLOCKEDand cost nothing, so such a run costs about the start fee. - If you set a maximum cost per run, the Actor stops before it. The last speech-to-text text may then be cut (
TRUNCATED).
Cost examples
Measured runs on the FREE plan prices:
| Scenario | Input scope | Expected item/event count | Base charge | Optional charge | Stop/cap behavior |
|---|---|---|---|---|---|
| One video with captions (prefill) | 1 link, 2048 MB | 2 apify-actor-start, 1 video | $0.0059 | none | โ |
| All links invalid | 1 invalid link, 2048 MB | 2 apify-actor-start | $0.005 | none | run ends Failed |
| 1,000 videos that are not found | 1,000 links, 2048 MB | 2 apify-actor-start, 1,000 video-checked | $0.105 | none | took 140 s |
| 1,000 videos, captions only | 20 profiles ร 50 videos, fallbackToSpeechToText: false, 1024 MB | 1 apify-actor-start, 1,000 video | $0.9025 | none | took 133 s |
| 60 newest videos with speech-to-text | 3 profiles ร 20 videos, 2048 MB | 2 apify-actor-start, 60 video, 154 speech-10-seconds | $0.059 | $0.308 | took 533 s |
| A 1-minute video without captions | 1 link, 2048 MB | 2 apify-actor-start, 1 video, 6 speech-10-seconds | $0.0059 | $0.012 | โ |
Limits
- 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.
- TikTok can change its pages or refuse requests. The Actor retries through Apify Proxy; rows it still cannot get are marked
SKIPPED_BLOCKEDand cost nothing.
API, export and integrations
- API: start a run with the same JSON as the input form and read the dataset items. See the Apify API docs.
- Export: download the dataset as JSON, CSV, Excel, XML or HTML. Use
outputFormat: "flat"for tables. - Scheduling: run on a schedule with
profilesandskipProcessed: trueto get only new videos each time. - Webhooks / no-code: use Apify integrations (Make, Zapier, n8n, webhooks) to send each new row on; the next system reads
transcriptandvideoUrl. - Subtitles: with
saveSubtitleFiles: truethe SRT, VTT and TXT links are infiles.
Use with AI agents (MCP)
-
MCP server URL with only this Actor:
https://mcp.apify.com?tools=cliqtomedia/tiktok-transcript. -
Smallest useful input:
{"videoUrls": ["https://www.tiktok.com/@apifytech/video/7398101551744552225"]} -
Key output fields:
transcript(full text),segments(timed lines),chunks(pieces with times for long context),statusandnoTranscriptReason(why a video has no text),videoUrl. -
One video with captions takes a few seconds and costs $0.0059 on FREE ($0.005 start fee at 2048 MB + $0.0009 per video). Videos without captions take about 3 seconds of run time per 10 seconds of audio and add $0.002 per 10 seconds.
-
Limits: up to 1,000 videos per run, public videos only, speech-to-text up to
maxSpeechMinutesPerVideo(10 min by default) per video.
Troubleshooting
A video has no transcript
Symptom: status is partial and transcript is empty.
Likely reason: see errorCode and noTranscriptReason:
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 |
ABORTED | You aborted the run first |
TRUNCATED | Speech-to-text stopped at your maximum cost per run; the text is cut |
DOWNLOAD_ERROR | The video file did not download (larger than 300 MB, empty or a download error) |
LOGIN_REQUIRED | TikTok gives this video's file only after login |
NETWORK_ERROR, BLOCKED | TikTok did not answer or refused the request for the video file |
Check: the reason text. Action: turn on fallbackToSpeechToText, raise maxSpeechMinutesPerVideo, the run timeout or the maximum cost, as the reason says. For download, login or network errors, run the video again later; these rows cost one video event and no speech charge.
A link returns not_found or error
Symptom: status is not_found (NOT_FOUND, PRIVATE_ACCOUNT, NO_VIDEOS) or error (INVALID_URL, RUN_VIDEO_LIMIT).
Likely reason: the video was deleted, the account is private, the text is not a TikTok link, or the run already took 1,000 videos.
Check: open the link in a private browser window.
Action: fix or remove the link, or move extra profiles to another run. not_found rows cost one video-checked ($0.0001); error rows cost nothing. If every link is invalid, the run ends as Failed and pays only the start fee.
The run ends with SOURCE_ERROR
Symptom: some rows have SKIPPED_BLOCKED and RUN_SUMMARY shows reason SOURCE_ERROR.
Likely reason: TikTok refused requests even through Apify Proxy, refused 3 videos in a row, or did not answer for over 45 seconds (NETWORK_ERROR, then SKIPPED_BLOCKED).
Check: the rows that are complete are saved and charged as normal.
Action: run again later with the same input; use skipProcessed to avoid the videos you already have.
FAQ
Do I need a TikTok account or cookies?
No. The Actor reads only public pages, without login, cookies or your own proxy.
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.
Can I get the text in another language?
Set language to use TikTok's captions in that language when TikTok has them, or translateToEnglish to get English for every video.
Related Actors
- YouTube Transcript Scraper: Subtitles & Timed Text โ the same kind of timed text for YouTube videos.
- Audio & Podcast Transcriber (Speech to Text) โ speech to text for audio and video files from other sources.
- Social Video Downloader: TikTok, Instagram, X - No Login โ when you need the TikTok video file itself.
Support
For a bug, question or feature request, open the Actor's Issues tab on Apify. Include the run ID, the input links that failed and the errorCode. Never send tokens, cookies or private data.

