Get a video’s transcript
The transcript TikTok publishes for a video, by id or URL, as one block of text plus time-coded segments. Coverage first, because it decides whether this route is worth building on: 68% of 185 videos measured across 14 languages had one. TikTok transcribes spoken audio for most videos but not all, and never for a video with no speech. A photo carousel is 0% by nature — there is no audio to transcribe. The other two thirds of the value is that the translations are free: a video posted in another language usually carries an English track alongside its original, both already timed. A real one, video 7643251685871062280, returns originalLanguage es-ES with an es-ES track of 58 segments ("estas son las 7 noticias de ciencia más impactantes del día") and an en-US track of the same 58 segments ("here are the 7 most shocking science news of the day") — one request, one credit, two languages. A video with no transcript is a normal 200, not an error: for video 7686148096895569165 it is `"transcript": {"available": false, "originalLanguage": null, "durationSeconds": 58, "tracks": []}`, with notes carrying "No transcript is published for this video. TikTok transcribes spoken audio for most videos but not all, and never for a video with no speech." The duration is still filled in, and `pagesFetched` is still 1. Do not retry it. Track languages are BCP-47 in the conventional casing (language lowercase, script Titlecase, region UPPERCASE), so TikTok’s eng-US arrives as en-US and zho-Hans-CN as zh-Hans-CN. Compare them case-insensitively anyway, because upstreams are inconsistent about case. Billing: 1 credit.
/video-transcript Videos https://api.fetchlayer.dev/tiktok/video-transcript Headers
Authorization string required Bearer token — your FetchLayer API key.
Parameters
video string required A video URL or a numeric video id. Shortened share links are rejected — resolve them first.
format string optional json or markdown. Markdown returns a rendered summary instead of the structured record. (default: json)
timeoutMs integer optional Time limit for each individual page read, in milliseconds (max 60000). It bounds one page, not the whole request.
Response Fields
video-transcript
Get a video’s transcript
transport string The upstream source. Always "tiktok".
notes string[] Caveats you can act on — a private account, comments turned off, a list that ran out early, paging that has gone as deep as it goes. Empty when there are none. An empty result always comes with a note explaining it, never as an unexplained empty array.
pagesFetched number Pages of results read, which is what the request costs: one credit per page. resolve-url reports 0 and is not billed.
videoId string The video the transcript belongs to.
videoUrl string Canonical link to the video.
transcript.available boolean Whether a transcript came back. False is a normal 200, not a failure, and notes says why.
transcript.originalLanguage string BCP-47 tag for the language spoken in the video, or null when there is no transcript. Conventionally cased: language lowercase, script Titlecase, region UPPERCASE.
transcript.durationSeconds number Length of the video in seconds. Filled in even when available is false.
transcript.tracks object[] One entry per track. Empty when no transcript is published. A non-English video usually carries a free English track alongside its original, so expect two.
transcript.tracks[].language string BCP-47 tag for this track, e.g. en-US or es-ES. Compare case-insensitively — upstream casing is not consistent.
transcript.tracks[].isOriginalLanguage boolean True on the track in the language actually spoken in the video. The translation alongside it is false.
transcript.tracks[].isAutoGenerated boolean True when TikTok generated the captions rather than the account supplying them.
transcript.tracks[].source string How the text was obtained — "captions" for a published caption track.
transcript.tracks[].text string The whole track, one caption line per newline.
transcript.tracks[].segments object[] Time-coded lines, each with start, end and text, in seconds. null rather than absent when a source carries no timings.
Request
curl -X POST "https://api.fetchlayer.dev/tiktok/video-transcript" \
-H "Authorization: Bearer ss-your-key" \
-H "Content-Type: application/json" \
-d '{"video":"7685115221458930957"}'Response
{
"transport": "tiktok",
"notes": [],
"pagesFetched": 1,
"videoId": "7685115221458930957",
"videoUrl": "https://www.tiktok.com/@_/video/7685115221458930957",
"transcript": {
"available": true,
"originalLanguage": "en-US",
"durationSeconds": 82,
"tracks": [
{
"language": "en-US",
"isOriginalLanguage": true,
"isAutoGenerated": false,
"source": "captions",
"text": "NASA's future depends on the people,\nmissions, and the networks that connect them.\nThis week had all three. Here's what's new in your NASA minute.\n…",
"segments": [
{
"start": 0.3,
"end": 2.14,
"text": "NASA's future depends on the people,"
},
{
"start": 2.141,
"end": 4.22,
"text": "missions, and the networks that connect them."
},
{
"start": 4.221,
"end": 7.88,
"text": "This week had all three. Here's what's new in your NASA minute."
}
]
}
]
}
}