TikTok Transcript Scraper - $0.40 per 1,000 avatar

TikTok Transcript Scraper - $0.40 per 1,000

Pricing

from $0.40 / 1,000 transcript scrapeds

Go to Apify Store
TikTok Transcript Scraper - $0.40 per 1,000

TikTok Transcript Scraper - $0.40 per 1,000

No caption track, no charge - a TikTok without one has nothing to transcribe. The rest come back as full transcript, timed segments, SRT and WebVTT, detected language, plus video id, author, caption and view count. $0.40 per 1,000 transcripts.

Pricing

from $0.40 / 1,000 transcript scrapeds

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

TikTok Transcript Scraper

Paste TikTok video links, bare video ids or vm.tiktok.com share links, and get the spoken words back as text. Every row carries the full transcript, the timed segments behind it, the detected language, and the video it came from: id, author, caption, duration, upload date and view count.

No account to set up, no cookies to paste, no browser, no API key.

  • It reads the caption track TikTok itself generates for the video, so the words match what the app shows on screen. Nothing is re-transcribed and nothing is guessed.
  • Every row ships four shapes of the same transcript: flat text, timed segments, ready-made srt, and the original vtt.
  • A video with no speech is never charged. It comes back as a free diagnostic row naming the video, so you can see what was skipped.
  • Ask for a specific language and you get the translated caption track when TikTok has one, with isTranslated marking those rows.
  • Up to 1,000 links per run, fetched in parallel, deduplicated before anything is billed.
  • Empty input returns one labelled sample row, free.

Price

$0.40 per 1,000 transcripts. Plus $0.0005 per run as the platform start fee, billed per gigabyte of run memory, so exactly that on the default 1 GB.

No volume tiers, no minimum spend, no subscription.

TranscriptsTotal
100$0.0405
1,000$0.4005
10,000$4.0005
100,000$40.0005

What gets charged

  • One transcript-scraped event per transcript row written to the dataset. Nothing else is metered per row.
  • Free: the sample row an empty run returns, and every diagnostic row. They all carry "charged": false.
  • A video with no caption track is a free NO_TRANSCRIPT row, not a charge.
  • Deleted, private, age-restricted and region-locked videos are free diagnostic rows too.
  • A link pasted twice, or pasted once as a share link and once as a full URL, is fetched once and charged once.
  • A run that finds nothing costs the start fee and nothing else.
  • Rows never leave the dataset without a charge and are never charged without a row. The billed event is a named one, so nothing is quietly attached to apify-default-dataset-item.

Input

{
"videoUrls": [
"https://www.tiktok.com/@baobei55555j/video/7516208601434819862",
"https://www.tiktok.com/@studywithlizzz/video/7657803613355412766",
"7673152431932378389"
],
"maxItems": 10,
"concurrency": 6
}
FieldWhat it does
videoUrlsThe videos you want transcribed. A full link, a vm.tiktok.com or vt.tiktok.com share link, or the bare numeric video id. All three work and you can mix them. Up to 1,000 per run.
maxItemsHow many transcripts to return at most. The list is read in order and the run stops as soon as it has this many, so it's a spend cap as much as a row cap. Links past that point cost nothing. Default 10, hard ceiling 5,000.
languageA language code such as es, fr, de or ja. When TikTok holds a translated caption track for the video you get that one and the row is marked isTranslated: true. When it doesn't, you get the original spoken track instead of an error. Leave empty for the original.
concurrencyHow many videos to read at once. Default 6, maximum 12. Lower it on a very long list if you want to be gentle. There's no reason to raise it for small runs.
sessionCookiesOptional, and empty is the normal case. See Age-restricted videos.
proxyUrlsLeave empty. Only for callers who want traffic to leave through proxy servers they already pay for, as http://user:pass@host:port.

Run it with empty input and you get one labelled sample row, free.

Output

One row per transcript. This is a real row from a real run:

{
"ok": true,
"charged": true,
"recordType": "transcript",
"videoId": "7516208601434819862",
"url": "https://www.tiktok.com/@baobei55555j/video/7516208601434819862",
"inputUrl": "https://www.tiktok.com/@baobei55555j/video/7516208601434819862",
"authorUsername": "baobei55555j",
"authorName": "Baobei5",
"authorUrl": "https://www.tiktok.com/@baobei55555j",
"caption": "Real NASA Footage? Scientist Walks Moon! #NASA #MoonMission #MoonLanding #Space #Astronaut",
"hashtags": ["NASA", "MoonMission", "MoonLanding", "Space", "Astronaut"],
"durationSeconds": 8,
"createdAt": "2025-06-15T16:08:11.000Z",
"language": "eng-US",
"languageCode": "en",
"languageName": "English",
"isAutoGenerated": true,
"isTranslated": false,
"captionSource": "ASR",
"text": "So, guys, we've just landed on the moon. And as you can see, Tori, this view is insane. It's freezing out here. This is just day 1. More to come.",
"wordCount": 30,
"characterCount": 145,
"segmentCount": 5,
"segments": [
{
"start": 0,
"end": 0.46,
"startTime": "00:00:00.000",
"endTime": "00:00:00.460",
"text": "So, guys,"
},
{
"start": 0.461,
"end": 1.741,
"startTime": "00:00:00.461",
"endTime": "00:00:01.741",
"text": "we've just landed on the moon."
}
],
"srt": "1\n00:00:00,000 --> 00:00:00,460\nSo, guys,\n\n2\n00:00:00,461 --> 00:00:01,741\nwe've just landed on the moon.",
"vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:00.460\nSo, guys,\n",
"availableLanguages": ["eng-US"],
"playCount": 40900,
"likeCount": 795,
"commentCount": 24,
"shareCount": 18,
"musicTitle": "original sound - aiunderstandyou4",
"coverUrl": "https://p16-common-sign.tiktokcdn.com/tos-no1a-p-0037-no/o8aRuyBFEiAfIwCTGAikA7CAF2u4fVUOog4Bgt~tplv-tiktokx-origin.image",
"scrapedAt": "2026-08-16T15:44:23.728Z"
}

Field notes

  • text is the whole transcript as one readable string, with caption line breaks collapsed and stray spaces before punctuation cleaned up. The words themselves are untouched.
  • segments is the same transcript as timed cues: start and end in seconds, startTime and endTime as HH:MM:SS.mmm, and the line of text. Use this for clipping, search-inside-video, or lining a transcript up with the footage.
  • srt is the cues rebuilt as a standard SRT file, ready to save as .srt.
  • vtt is the original WebVTT exactly as served, for anyone who wants the untouched source.
  • isAutoGenerated is true when the track came from speech recognition rather than being written by a person.
  • isTranslated is true when the track is a machine translation rather than the language actually spoken.
  • language is the track's own code, like eng-US. languageCode is the two-letter form and languageName the English name, so you don't have to map it yourself.
  • availableLanguages lists every caption track TikTok exposed for that video on that request, so you can see what else could have been asked for.
  • durationSeconds is the video length, not the transcript length. A long video with two spoken words has a long duration and a short transcript.
  • playCount is views at read time. It keeps moving.
  • inputUrl is exactly what you pasted, so rows join back to your own list. url is the canonical link with the real author handle filled in.

Real rows carry "charged": true. Sample rows carry "_sample": true, diagnostic rows carry "_diagnostic": true and an errorCode. Neither is billed.

How it works

It asks TikTok for the video's own page the way a phone browser does and reads the caption track out of the data the page already carries. One request per video, no page rendering, no headless browser, no login.

The caption file itself is fetched from TikTok's subtitle store and parsed into timed cues, then rebuilt into plain text and SRT. Requests leave through a rotating pool of addresses, so a per-address rate limit is answered by moving rather than waiting. Videos are read in parallel, with a small ladder of retries per video so one bad moment on one address doesn't cost you a row. Two independent readers run against every page, so a layout change on TikTok's side doesn't take the Actor down with it.

Age-restricted videos

Every video is read without an account. That's the fast path and it's what nearly all of them answer.

A few won't. An age-restricted video is the clear case: TikTok shows it only to a signed-in viewer. Those come back as free NOT_FOUND diagnostic rows and the run carries on with the rest of your list.

If you need them, paste your own TikTok cookie into sessionCookies:

  1. Sign in to TikTok in Chrome.
  2. F12 → Application → Cookies → https://www.tiktok.com.
  3. Copy the sessionid value and pass it as "sessionid=<value>".

The cookie goes to TikTok's video pages and nowhere else. Caption files come from a CDN and no cookie is sent with them. Its value is never written to the log. You can pass several and the run rotates between them. The run's status line reports sessionState so you can tell which kind of run you had: keyless when nothing needed an account, then ok, degraded or exhausted.

How much of TikTok actually has a transcript

TikTok creates a caption track when it detects speech, and creators can upload their own. It doesn't create one for a clip that's only music, only sound effects, or silent, and a photo slideshow has no audio track at all.

On a random 120-video sample pulled from TikTok's own topic pages, 85 videos had a caption track and 35 did not. Talking-head, tutorial, news and review content is close to universally covered. Dance, comedy skits without dialogue, and music edits usually aren't.

The 35 that had nothing cost nothing. Each came back as a free NO_TRANSCRIPT row naming the video. So the worst case for a list of links that turns out to be all music is a run that bills the start fee and nothing else.

What people use it for

  • Feeding TikTok content to a language model for summaries, topic tagging or translation, without paying a speech-to-text bill for audio that already has captions.
  • Repurposing short video into blog posts and newsletters. The transcript is the first draft.
  • Content research at scale. Pull the transcripts of a hundred videos in a niche and search them for the phrases and objections that keep coming up.
  • Subtitle work. Take the srt or vtt straight into an editor, retime it, translate it.
  • Accessibility archives, where the spoken content of published videos has to be kept in text form.
  • Building a searchable index of a creator's back catalogue, so "which video mentioned X?" becomes a text query.
  • Hook analysis. segments gives you the first three seconds of speech separately from the rest, which is the part that decides whether anyone watches.

Reading the output

  • Real rows carry "charged": true and "recordType": "transcript". One billed event each.
  • The sample row carries "_sample": true and "charged": false. There's exactly one, only when the input had no videos.
  • Diagnostic rows carry "_diagnostic": true, "charged": false and an errorCode: NO_TRANSCRIPT when the video has no caption track, NOT_FOUND when it's deleted, private, age-restricted or region-locked, BAD_INPUT when a line wasn't a TikTok link, BLOCKED when the target refused the request, NETWORK when it couldn't be reached, TIME_BUDGET when time ran out. Each carries a plain-English error and the inputUrl it belongs to.

Filter on charged == true and you have exactly the rows you paid for.

Limits

  • A video only has a transcript if TikTok generated a caption track for it or the creator uploaded one. Roughly seven in ten videos in a mixed sample have one. Silent clips, music-only edits and photo slideshows don't, and those come back as free diagnostic rows.
  • Nothing here listens to audio. If TikTok has no caption track, this Actor won't invent one. It tells you the track is missing instead.
  • Auto-generated captions are speech recognition, so they carry its mistakes. Proper nouns, brand names, numbers and heavy accents are where they slip. Punctuation and sentence boundaries are approximate.
  • Translated tracks (isTranslated: true) are machine translations, not human subtitles.
  • Which translated languages exist is TikTok's decision per video, not a setting. Asking for a language TikTok doesn't have for that video returns the original spoken track, marked as such, rather than failing.
  • On-screen text burned into the picture (stickers, overlays, meme captions) isn't part of the caption track and isn't returned.
  • Private, friends-only, deleted, age-restricted and region-locked videos come back as free diagnostic rows saying which it was.
  • Timings come from the caption file, so they're cue timings rather than word-level timings. There's no per-word timestamp.
  • View, like, comment and share counts are a snapshot at read time.
  • Hard ceilings: 1,000 links and 5,000 transcripts per run.
  • Live videos and stories are out of scope. This reads regular posted videos.
  • The run works down your list until it has the number of transcripts you asked for, so extra links are a useful buffer against videos that turn out to have none. It gives up early only when a list is almost entirely caption-less, roughly three fruitless lookups per transcript requested and never fewer than 25, and it says so in a free diagnostic row rather than failing.

Questions

What happens if a video has no captions?

One free diagnostic row with errorCode: "NO_TRANSCRIPT" naming the video, and the run carries on.

Can I paste share links from the app?

Yes. vm.tiktok.com, vt.tiktok.com and tiktok.com/t/ links are all followed to the real video. You can also paste the bare numeric video id, and mix all of these in one list.

Does it transcribe the audio?

No, deliberately. It reads the caption track TikTok already made, which is the same text the app shows on screen. That's faster, it costs a fraction of running speech-to-text, and for the videos that have it, it's the better transcript.

Can I get the transcript in another language?

Set language to a code like es or fr. When TikTok holds a translated caption track for that video you get it, marked isTranslated: true. When it doesn't, you get the original spoken track rather than an error, so a batch never dies because one video wasn't translated.

Do I need a proxy?

No. The run brings its own egress and its cost is already inside the price. proxyUrls exists only for callers who want traffic to leave through servers they already own.

Will the run fail if something goes wrong?

No. A blocked, deleted or caption-less video produces an uncharged diagnostic row and the run still finishes as succeeded. A failed run would still bill the start fee, which would mean paying to be told something went wrong.

Can I run it on a schedule?

Yes. Nothing is held between runs. Use videoId to work out which rows are new since last time.