TikTok Transcripts - Captions, SRT, Speech-to-Text avatar

TikTok Transcripts - Captions, SRT, Speech-to-Text

Pricing

from $5.00 / 1,000 captioned video transcripts

Go to Apify Store
TikTok Transcripts - Captions, SRT, Speech-to-Text

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

Heim AI

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

4 days ago

Last modified

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 idkaz_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
OutputDataset 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)

  1. 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.
  2. Schedule the Task (hourly/daily) when the URL list is stable — e.g. a creator watchlist you refresh elsewhere.
  3. Webhook on SUCCEEDED to your endpoint / Zapier / Make — pull defaultDatasetId and process only type === "transcript" rows.
  4. Cap spend on every automated run with maxTotalChargeUsd. When the cap hits, remaining videos become type: "error" skipped rows with errorCode: "charge_limit_reached" — no surprise bill, no silent free transcripts.
  5. 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 use kaz_kakyo/audio-transcriber.

Long runs checkpoint a per-video billing ledger (RESERVEDCHARGEDDELIVERED) — 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 --> …"
}
FieldWhen present
transcript, videoId, author, title, durationSeconds, language, sourcealways on success
subtitleSource, machineTranslatedcaption-derived rows (source: "captions")
languageFallbacktrue when preferred languages did not match and another track was used
availableLanguagescaption-derived rows
segmentsincludeTimestamps: true
srtincludeSrt: true
sttModel, minutesBilled, confidenceSTT fallback rows (source: "stt")
segmentsUrl / srtUrlrare — 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 transcript by default for RAG / MCP context packing.

Pricing

EventPriceWhen
Captioned video$0.005Successful caption-derived transcript (one charge per video)
STT minute$0.012Per started audio-minute of Deepgram fallback (ceil(duration/60), min 1)
Actor start$0.005Per 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_video error rows. Empty/whitespace entries become invalid_url. Photo posts (/@user/photo/{id}) become error rows without fetching.
  • languages — optional preferred codes in order (default prefers en). Accepts en, eng, or eng-US. Within a language: creator > ASR > MT. Unmatched prefs fall back with languageFallback: true.
  • includeTimestamps — adds segments[] with { start, duration, text }.
  • includeSrt — adds an .srt-format string.
  • transcribeMissingCaptions — default true; when false, no-caption videos become no_captions error 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_post error 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 / errorCode on 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.