TikTok Transcript Scraper avatar

TikTok Transcript Scraper

Pricing

$0.90 / 1,000 transcripts

Go to Apify Store
TikTok Transcript Scraper

TikTok Transcript Scraper

Export the captions TikTok already has on public videos as timestamped segments plus full text, by video URL. Original spoken language by default, or pick one. Videos without captions return success:false, cost $0, and never break the batch. No AI transcription. $0.90 per 1,000 transcripts.

Pricing

$0.90 / 1,000 transcripts

Rating

0.0

(0)

Developer

apihq dev

apihq dev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 hours ago

Last modified

Share

Export the captions that already exist on public TikTok videos as clean JSON from their video URLs: timestamped segments, the full text in one string, the caption language and source, and the video's author and counts. Existing TikTok captions only: this Actor does no AI transcription. A video without captions returns a free success: false row with code: TIKTOK_NO_CAPTIONS. No TikTok account, no API key, no browser.

The contract is simple: you only pay for transcripts delivered. A video with no captions, a deleted video, or a bad URL comes back as a success: false row while the rest of the batch keeps going. $0.90 per 1,000 transcripts. Failed videos cost $0, and there is no start fee.

See one run

Input:

{
"postURLs": [
"https://www.tiktok.com/@apifytech/video/7398101551744552225",
"https://www.tiktok.com/@scout2015/video/6718335390845095173"
]
}

What comes back:

  • 1 success: true transcript for the apifytech video, billed: TikTok's English auto captions as 12 timestamped segments (the first is "Are you doing research in HR" at 0.02 s), the same text joined in full_text, and the video's author, duration, and counts
  • 1 success: false row, code: TIKTOK_NO_CAPTIONS, for the scout2015 video, which has no captions on TikTok, not billed
  • Run status: SUCCEEDED
  • Charge: 1 delivered transcript x $0.0009 = $0.0009

Videos with captions return billed transcripts, videos without captions return free error rows in the same dataset, and the run still succeeds, so one captionless video never costs you a batch.

Why this Actor

  • You pay only for transcripts. Billing fires on an explicit per-transcript event, not on dataset writes. One delivered transcript is one charge, however many segments it has. Rows for videos without captions are free, and there is no per-run start fee.
  • Parsed, not raw. You get transcript segments with text, start, and duration in seconds, plus full_text, instead of a WebVTT file you have to parse yourself.
  • You know where the text came from. Every transcript says its language, its source (ASR for TikTok's own auto captions, MT for TikTok's machine translation, creator for captions the creator added), and whether it is auto-generated or translated. available_tracks lists every caption track the video has.
  • Every miss is machine-readable. Each failure carries a stable code (TIKTOK_NO_CAPTIONS, TIKTOK_LANGUAGE_UNAVAILABLE, TIKTOK_VIDEO_UNAVAILABLE, VALIDATION_FAILED, ...), so your pipeline branches on the reason without parsing English.
  • Same shape as our YouTube transcripts. Field names (video_id, language, transcript, is_auto_generated, available_tracks, code, request_id) match the YouTube Transcript Scraper, so one pipeline can read both.

Best for

AI and data workflows that turn TikTok videos into text: RAG pipelines and LLM datasets, search over what creators actually say, sentiment, topic, and brand-safety analysis, content research on known videos, and subtitle and accessibility tooling. The free no-caption rows and stable error codes matter most when transcripts feed an automated pipeline, where one captionless video should never take down the batch. It works fine for one-off manual pulls too.

Input example

A single video with TikTok captions:

{
"postURLs": ["https://www.tiktok.com/@apifytech/video/7398101551744552225"]
}

A batch mixing videos with and without captions, copied from the browser with tracking parameters (they are ignored, and copies of the same video run once). The scout2015 video has no captions and returns a free TIKTOK_NO_CAPTIONS row:

{
"postURLs": [
"https://www.tiktok.com/@apifytech/video/7398101551744552225?is_from_webapp=1&sender_device=pc",
"https://www.tiktok.com/@renreports/video/7307726351291960622",
"https://www.tiktok.com/@scout2015/video/6718335390845095173",
"https://m.tiktok.com/@apifytech/video/7398101551744552225"
]
}

A Spanish video in English. The video is spoken in Spanish and TikTok offers an English machine translation of its captions; "language": "en" returns that translation (source: "MT", is_translated: true). Without language you get the original Spanish captions:

{
"postURLs": ["https://www.tiktok.com/@blandon_esther/video/7498938601602813227"],
"language": "en"
}
FieldTypeDefaultWhat it does
postURLsarray of stringsTikTok video URLs, up to 50 unique videos per run. Copies of the same video (with www., m., a query string, or a trailing slash) are run and billed once.
languagestringblankCaption language to return, such as en, en-US, or es. Blank returns the captions in the video's original spoken language. When set, an exact match wins, then the same language in another region (en matches en-US). A TikTok translation is returned only when you ask for its language. Another language is never substituted.

Output example

One record per video. The transcript for the apifytech video (TikTok's English auto captions):

{
"success": true,
"video_id": "7398101551744552225",
"video_url": "https://www.tiktok.com/@apifytech/video/7398101551744552225",
"language": "en-US",
"language_raw": "eng-US",
"source": "ASR",
"is_auto_generated": true,
"is_translated": false,
"transcript": [
{ "text": "Are you doing research in HR", "start": 0.02, "duration": 1.4 },
{ "text": "or do you want to get a structured list of job listings", "start": 1.421, "duration": 2.32 },
{ "text": "without endlessly scrolling through?", "start": 3.742, "duration": 1.359 }
],
"full_text": "Are you doing research in HR or do you want to get a structured list of job listings without endlessly scrolling through? Indeed. What if I told you that you can get a vast amount of job data from any specific location without any coding experience? The tool is called India Scraper. All you have to do is type in a job title and a location and you'll get your data. Try it out now on appify. a slash. Indeed! Oh, and don't forget to follow us for more tips on how to automate mundane tasks!",
"available_tracks": [
{
"language_code": "en-US",
"language_raw": "eng-US",
"language_name": "English (United States)",
"source": "ASR",
"is_auto_generated": true,
"is_original": true
}
],
"metadata": {
"description": "Yes, you can scrape job listings #data in a minute!! #webscraping #techtiktok #job #automation ",
"create_time": 1722504752,
"create_time_iso": "2024-08-01T09:32:32.000Z",
"duration_seconds": 23,
"author_handle": "apifytech",
"author_name": "Apify",
"author_url": "https://www.tiktok.com/@apifytech",
"thumbnail_url": null,
"play_count": 595,
"digg_count": 21,
"comment_count": 0,
"share_count": 1
},
"submitted_video_url": "https://www.tiktok.com/@apifytech/video/7398101551744552225"
}

(3 of 12 segments shown; full_text is complete. The leading emoji of the description is dropped here. The captions are TikTok's own, mistakes included: "India Scraper" and "appify" are what TikTok's auto captions heard.)

A video without captions lands in the same dataset and is not charged:

{
"success": false,
"video_id": "6718335390845095173",
"submitted_video_url": "https://www.tiktok.com/@scout2015/video/6718335390845095173",
"code": "TIKTOK_NO_CAPTIONS",
"error": "TikTok exposes no captions for this video",
"request_id": "req_4c7e2a9f0b1d4e8a9c3f5b62",
"status_code": 422
}

So does a video that has captions, just not in the language you asked for (here "language": "fr" on the English apifytech video). The message lists the languages that do exist:

{
"success": false,
"video_id": "7398101551744552225",
"submitted_video_url": "https://www.tiktok.com/@apifytech/video/7398101551744552225",
"code": "TIKTOK_LANGUAGE_UNAVAILABLE",
"error": "No TikTok captions in the requested language. Available: en-US",
"request_id": "req_9a1f3e5c7b2d4f60a8e1c3d5",
"status_code": 422
}

Split hits from misses on the success field. Quote request_id in any support issue and we can trace the exact request.

What you get

Every transcript is one record with success: true. Any value TikTok does not report is null:

FieldTypeWhat it is
successbooleantrue for a delivered transcript (billed), false for a video without one (not billed).
video_idstringThe video ID.
video_urlstringThe canonical video URL, with the author's current handle.
languagestringLanguage of the returned captions as a standard tag, such as en-US or es-ES.
language_rawstringThe same language as TikTok labels it, such as eng-US.
sourcestring or nullWhere the captions come from: ASR (TikTok's auto captions), MT (TikTok's machine translation), creator (captions the creator added), another TikTok label, or null when TikTok does not say.
is_auto_generatedboolean or nulltrue for TikTok's auto captions and translations, false for creator captions.
is_translatedboolean or nulltrue when the captions are a TikTok translation rather than the spoken language.
transcriptarrayTimestamped segments: text, start, and duration, both in seconds.
full_textstringEvery segment's text joined with one space.
available_tracksarrayEvery caption track the video has: language_code, language_raw, language_name, source, is_auto_generated, is_original (true for the spoken language).
metadataobjectdescription (the post caption, not spoken text), create_time / create_time_iso (Unix seconds and ISO 8601 UTC), duration_seconds, author_handle, author_name, author_url, thumbnail_url, play_count, digg_count (likes), comment_count, share_count.
submitted_video_urlstringThe input URL this record answers, as you gave it.

IDs are strings because TikTok's 19-digit IDs do not fit in a JavaScript number.

Videos without a transcript carry success: false, video_id (when the URL could be read), submitted_video_url (the URL you gave), a machine-readable code, a human-readable error, the service request_id, and the HTTP status_code. They are not charged:

CodeMeaning
TIKTOK_NO_CAPTIONSTikTok has no captions for this video. Common for music-only clips and photo posts.
TIKTOK_LANGUAGE_UNAVAILABLEThe video has captions, but none in the requested language. The error lists the available languages. Also returned when blank language meets a video whose only captions are TikTok translations.
TIKTOK_EMPTY_TRANSCRIPTTikTok's caption track exists but contains no text.
TIKTOK_VIDEO_UNAVAILABLEThe video is deleted, private, or otherwise unavailable.
TIKTOK_UNAVAILABLETikTok did not serve this video and gave no reason.
TIKTOK_BLOCKEDTikTok refused the request after an automatic retry.
TIKTOK_RATE_LIMITEDTikTok rate-limited the request after an automatic retry.
TIKTOK_TIMEOUTTikTok did not answer in time after an automatic retry.
DEADLINE_EXCEEDEDThe video request hit its 30-second deadline.
VALIDATION_FAILEDThe URL is not a supported TikTok video URL (including short links and /photo/ URLs), the language value is not a language code, or TikTok rejected the video ID.
NO_INPUTNo usable postURLs were given. The run ends successfully with this single row.

Pricing

Pay per event. One transcript charge per transcript delivered: $0.0009 each, which is $0.90 per 1,000 transcripts. The charge fires only after the transcript record lands in your dataset.

  • One delivered transcript is one charge, whether it has 3 segments or 300.
  • 1,000 delivered transcripts cost $0.90.
  • Videos without captions, language misses, unavailable videos, and bad URLs cost $0.
  • There is no per-run start fee, so a run that delivers nothing costs nothing.

Platform compute is included in the per-transcript price. Cap the maximum spend of a single run from Apify's Run Limits panel; the Actor checks the cap before each video and stops cleanly when the budget runs out.

What this Actor does not do

Honest scope, so you know before you run it:

  • Existing TikTok captions only. It returns the captions TikTok already has on the video. It does no AI transcription, does not download audio, and does not read on-screen text (no OCR). A video without captions returns a free success: false row with code: TIKTOK_NO_CAPTIONS; many TikTok videos, especially music-only clips and photo posts, have none.
  • No other languages invented. It returns a translation only when TikTok itself offers one in the language you asked for. It never translates captions on its own and never substitutes another language.
  • Video URLs only. It reads the videos you give it. It does not find videos from a profile, hashtag, sound, or search query.
  • Full video URLs only. Short share links (vm.tiktok.com/..., vt.tiktok.com/...) and /photo/ URLs come back as a free success: false row with code: VALIDATION_FAILED. Open a short link in a browser and paste the full https://www.tiktok.com/@user/video/<id> URL instead.
  • No downloads. It does not return video, audio, or caption files, or links to them. The transcript is in the record.
  • No login-only content. Private videos and anything that needs a TikTok account return success: false.

How to use this Actor

  1. Open the Actor in the Apify Console.
  2. Paste one or more TikTok video URLs into postURLs. Up to 50 unique videos run per job. Optionally set language (such as en or es).
  3. Click Start. Each video produces one record: success: true with the transcript, or success: false with the reason. Only delivered transcripts are charged.

The Actor is also callable from the Apify API and every official integration (Make, Zapier, n8n, Slack, webhooks). The API tab in the Console has ready-to-paste JavaScript, Python, and curl snippets.

Reliability

A video without captions never fails the batch. No captions, a language miss, a deleted video, or a bad URL becomes a success: false record with a specific code. The run keeps going and finishes successfully, even when no video in it had captions.

You never pay for a miss. Billing fires on an explicit per-transcript charge event, not on dataset writes, so success: false records are free. There is no per-run start fee either.

Empty transcripts are failures. A caption track that contains no text comes back as success: false with code: TIKTOK_EMPTY_TRANSCRIPT and is not billed. You never pay for a blank transcript.

Automatic retry, then a clear answer. A blocked, rate-limited, or slow request is retried once from a fresh network identity before the video is reported as failed. Each video runs under a 30-second deadline, so a stalled page returns a success: false record with code: DEADLINE_EXCEEDED instead of hanging your run.

No duplicate charges. The same video pasted several times in one input (with m., a query string, or a trailing slash) is fetched and charged once per run.

Genuine faults are not hidden. An outage of our backend, a caption file TikTok changed in a way we cannot read, or a failure to write or bill results fails the run without a charge for the failed video, so a broken run never looks like a clean one with missing data.

FAQ

Does it transcribe videos without captions?

No. The Actor returns only the captions TikTok already has on the video. A video without them comes back as a free success: false row with code: TIKTOK_NO_CAPTIONS. There is no AI speech-to-text fallback, so you never pay for a transcript TikTok did not make.

Is it the same as TikTok auto captions?

Yes. source: "ASR" means TikTok's own automatic captions, the ones viewers can turn on in the TikTok app. TikTok generated them; this Actor runs no speech recognition. Captions TikTok marks as not auto-generated come back as source: "creator", TikTok's translations as source: "MT", and null means TikTok did not say.

Which languages?

Whatever TikTok has for the video. By default you get the captions in the video's original spoken language. Set language (such as en, en-US, or es) to choose: an exact match wins, then the same language in another region. If TikTok offers a machine translation in that language, you get it with is_translated: true. If the video has no captions in that language, you get a free TIKTOK_LANGUAGE_UNAVAILABLE row that lists the languages it does have. available_tracks on every transcript shows all of them.

Can I get plain text only?

Use full_text: every segment joined into one string with single spaces. Ignore transcript if you do not need the timestamps.

Do short links, photo posts, or profiles work?

No. Use full video URLs: https://www.tiktok.com/@user/video/<id>, also with m.tiktok.com, without www., with a query string, or with a trailing slash. Short links (vm.tiktok.com, vt.tiktok.com) and /photo/ URLs return a free VALIDATION_FAILED row. The Actor does not list a profile's videos.

Do I need a TikTok account or API key?

No. The Actor reads public video pages directly. There is nothing to log into and no TikTok developer key to provision. (You run it with your normal Apify account, like any Actor.)

How much does it cost?

$0.90 per 1,000 delivered transcripts, one charge per transcript regardless of its length. Videos without captions, other failed videos, and empty runs cost $0, and there is no start fee.

Why is a field null?

TikTok did not report it for that video. The Actor never fills a gap with a guessed 0 or false, so null always means "unknown", not "none".

Can I also get the video stats or comments?

Yes, with the sibling Actors TikTok Video Scraper and TikTok Comments Scraper, which take the same postURLs and use the same failure-free billing. For YouTube, use the YouTube Transcript Scraper.

Can I use this Actor from my own code?

Yes. Use the Apify API or one of the official SDKs (Node.js: apify-client, Python: apify-client). The Console shows ready-to-paste code samples on the API tab.

Found a bug or want a feature?

Open an issue on this Actor's Issues tab and include the request_id from any error record you saw. We respond within one business day.