TikTok Transcript API — Captions and Timings by Video
Documentation menu
FetchLayer FetchLayer API

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.

POST /video-transcript Videos
https://api.fetchlayer.dev/tiktok/video-transcript
OpenAPI JSON

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."
          }
        ]
      }
    ]
  }
}