TikTok Transcripts - Captions, SRT, Speech-to-Text
Pricing
from $5.00 / 1,000 captioned video transcripts
TikTok Transcripts - Captions, SRT, Speech-to-Text
Extract TikTok video transcripts via API, MCP, or schedule — captions with timestamps, SRT subtitles, multi-language, optional Deepgram speech-to-text for videos without captions. $0.005 per captioned video. One JSON row per URL. No browser, no login.
Pricing
from $5.00 / 1,000 captioned video transcripts
Rating
0.0
(0)
Developer
Heim AI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
4 days ago
Last modified
Categories
Share
TikTok Transcripts — Captions & Speech-to-Text from Video URLs
URL in → transcript out. Pass TikTok video links; get one JSON dataset row per video with the caption track (ASR / creator / MT) or optional Deepgram speech-to-text when captions are absent. No browser, no login. Built for MCP agents, API clients, and scheduled pipelines.
| Actor id | kaz_kakyo/tiktok-transcripts |
| Minimal input | { "tiktokUrls": ["https://www.tiktok.com/@user/video/…"] } |
| Cost | $0.005 per captioned video · $0.012/audio-minute STT fallback · $0.005/run start |
| Output | Dataset rows with type: "transcript" or type: "error" |
Call it (MCP / API / schedule)
MCP (agents)
{"actor": "kaz_kakyo/tiktok-transcripts","input": {"tiktokUrls": ["https://www.tiktok.com/@aespa_official/video/7401509513653734664"]}}
Optional extras agents usually want:
{"tiktokUrls": ["https://www.tiktok.com/@aespa_official/video/7401509513653734664"],"languages": ["en"],"includeTimestamps": true,"includeSrt": true,"transcribeMissingCaptions": true}
After the run, read the default dataset. Every row has a type discriminator — filter on "transcript"; treat "error" as per-video failure. Missing captions (when STT is off/unavailable), photo posts, private/region-blocked videos, bad URLs, duplicate aliases of the same video, and misconfigured PPE pricing become error rows and the run still SUCCEEDS (including all-failed batches) so agent mistakes do not look like platform outages. The run fails only on a post-charge delivery failure (charged but could not write the dataset).
API / apify-client
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('kaz_kakyo/tiktok-transcripts').call({tiktokUrls: ['https://www.tiktok.com/@aespa_official/video/7401509513653734664'],includeTimestamps: true,},{ maxTotalChargeUsd: 1.0 }, // hard budget for this run);const { items } = await client.dataset(run.defaultDatasetId).listItems();const transcripts = items.filter((i) => i.type === 'transcript');
Same shape via REST: POST /v2/acts/kaz_kakyo~tiktok-transcripts/runs with your token, then poll or attach a webhook.
Make it recurring (what sticky callers do)
- Save a Task in Console with your fixed options (
languages,includeTimestamps,includeSrt,transcribeMissingCaptions). Agents and cron jobs call the task id, not ad-hoc input. - Schedule the Task (hourly/daily) when the URL list is stable — e.g. a creator watchlist you refresh elsewhere.
- Webhook on
SUCCEEDEDto your endpoint / Zapier / Make — pulldefaultDatasetIdand process onlytype === "transcript"rows. - Cap spend on every automated run with
maxTotalChargeUsd. When the cap hits, remaining videos becometype: "error"skipped rows witherrorCode: "charge_limit_reached"— no surprise bill, no silent free transcripts. - Chain: any TikTok search/profile scraper that outputs video URLs → this actor. For YouTube captions use
kaz_kakyo/youtube-transcripts. For direct media file URLs usekaz_kakyo/audio-transcriber.
Long runs checkpoint a per-video billing ledger (RESERVED → CHARGED → DELIVERED) — a platform migration resumes without re-billing. Incomplete ledger entries surface as resumed_incomplete error rows (re-run those videos). Same video via two input URLs (canonical + bare id) yields one transcript and one duplicate_video error.
Output contract
One dataset item per input URL (plus skipped/invalid rows). Success shape:
{"type": "transcript","url": "https://www.tiktok.com/@aespa_official/video/7401509513653734664","videoId": "7401509513653734664","author": "aespa_official","title": "…","durationSeconds": 32,"language": "eng-US","source": "captions","subtitleSource": "ASR","machineTranslated": false,"languageFallback": false,"transcript": "Full caption text…","availableLanguages": [{ "language": "eng-US", "source": "ASR" }],"segments": [{ "start": 0.0, "duration": 2.1, "text": "…" }],"srt": "1\n00:00:00,000 --> …"}
| Field | When present |
|---|---|
transcript, videoId, author, title, durationSeconds, language, source | always on success |
subtitleSource, machineTranslated | caption-derived rows (source: "captions") |
languageFallback | true when preferred languages did not match and another track was used |
availableLanguages | caption-derived rows |
segments | includeTimestamps: true |
srt | includeSrt: true |
sttModel, minutesBilled, confidence | STT fallback rows (source: "stt") |
segmentsUrl / srtUrl | rare — oversized payloads spilled to the key-value store |
Failure / skip row (never charged):
{ "type": "error", "url": "https://…", "videoId": "…", "error": "…", "errorCode": "no_captions" }
Common errorCode values: invalid_url, photo_post, duplicate_video, video_unavailable, region_blocked, bot_gated, no_captions, stt_duration_unknown, pricing_unavailable, resumed_incomplete, input_cap_exceeded, charge_limit_reached, run_aborted. Overflow / budget-skip rows always carry an errorCode — do not branch on message text.
Download the dataset as JSON, CSV, Excel, or HTML from Console or the dataset API.
Why this one
- Captions-first, cheap. $0.005 per captioned video via TikTok's own ASR WebVTT tracks — no Whisper burn when captions exist.
- Honest STT fallback. Videos without captions (music/dance clips, many older posts) can optionally go through Deepgram at $0.012/audio-minute.
- Agent-safe. Bad/missing-caption/photo URLs become
type: "error"rows; the run still succeeds. - Transcript only. No likes, views, comments, or author profiles — sell the speech, not the engagement graph.
- Timestamps + SRT when you need them; plain
transcriptby default for RAG / MCP context packing.
Pricing
| Event | Price | When |
|---|---|---|
| Captioned video | $0.005 | Successful caption-derived transcript (one charge per video) |
| STT minute | $0.012 | Per started audio-minute of Deepgram fallback (ceil(duration/60), min 1) |
| Actor start | $0.005 | Per run |
Error / skipped rows are never billed. Cap spend with maxTotalChargeUsd on the run or task.
Input rules agents must follow
tiktokUrls(required) —/@user/video/{id},m.tiktok.com/v/{id}.html, shortlinks (vm.tiktok.com,vt.tiktok.com,/t/), or bare numeric ids (≥15 digits). Max 500 per run (maxItems: 500). Duplicates by video ID become one transcript +duplicate_videoerror rows. Empty/whitespace entries becomeinvalid_url. Photo posts (/@user/photo/{id}) become error rows without fetching.languages— optional preferred codes in order (default prefersen). Acceptsen,eng, oreng-US. Within a language: creator > ASR > MT. Unmatched prefs fall back withlanguageFallback: true.includeTimestamps— addssegments[]with{ start, duration, text }.includeSrt— adds an.srt-format string.transcribeMissingCaptions— default true; when false, no-caption videos becomeno_captionserror rows.deepgramApiKey— optional BYOK for the STT fallback (otherwise the zero-setup pool is used when available).
Limits (honest)
- Caption availability varies. Music/dance clips and many older videos often have no subtitle track — those need the STT fallback (or return
no_captions). - Photo posts unsupported — no speech track; returned as
photo_posterror rows. - No engagement metadata by design — transcript only (no likes/views/comments/profiles).
- STT needs a known duration — if page metadata has no usable duration, STT is refused (
stt_duration_unknown) so cost stays bounded. - STT media cap — videos longer than 60 minutes or with media over 120 MB are refused uncharged (
stt_duration_unknown/media_too_large). - Pricing must be configured — on PPE, if an event price is missing/zero the actor refuses premium delivery (
pricing_unavailable) rather than leaking free data. - Source drift risk — TikTok page JSON / CDN URLs can change; the captions path is HTTP-only and will need code updates if TikTok breaks the rehydration payload.
- Errors never fail the run — check
error/errorCodeon dataset rows.
See the Input tab for the full schema. See the API tab for run/dataset endpoints.
FAQ
Do I need a TikTok login? No. The actor fetches the public video page + subtitle CDN.
Captions vs STT? Captions are preferred when present (source: "captions"). STT runs only when captions are absent and transcribeMissingCaptions is true with a Deepgram key available (source: "stt").
Why did my URL fail? No captions (and STT off/unavailable), photo post, private/deleted, region-blocked, or bot gate. Check error / errorCode — the run status will still be SUCCEEDED.
How do I keep costs predictable on a schedule? Set maxTotalChargeUsd on the run/task. Prefer captioned videos when possible — STT minutes cost more.
Related actors? YouTube captions → kaz_kakyo/youtube-transcripts. Direct media files → kaz_kakyo/audio-transcriber.
If this saved you time, a Store review on the actor page helps a solo dev. Hit a problem? Open an issue.