TEST SITE: not indexed, not the live website. Placeholder button URLs in use: signup, login, dashboard, playground, api_base.

Save a TikTok Transcript as SRT and VTT Files

Subtitle files with a check.

  • 2 min read
  • Last verified
  1. TikTok URLand lang
  2. Request srt and vtttwo calls
  3. Check header and cues
  4. .srt and .vttUTF-8
Draft notice

Examples verified against the documented contract; live-API verification pending. Run tools/verify-live.sh with a real key and base URL, then remove this notice.

Overview

To save a TikTok transcript as SRT or VTT, request each format and write the response to a UTF-8 file.

  • Writes .srt and .vtt files.
  • Checks the first line and counts cues.
  • A missing language stops with a typed error.

The script asks for format=srt and format=vtt, writes both files and checks the header and the cue count. A missing language stops with the typed error and no file.

Marco edits short clips for a small studio. He wants a subtitle file per clip that he can drop into his editor, and a quick check that the file is not empty.

The script

srt_vtt.py
"""Save a TikTok transcript as .srt and .vtt files and check them.
Usage: python srt_vtt.py TIKTOK_URL [--lang en] [--out subs]"""
import argparse, os, re, sys
import requests

API = os.environ.get("TTA_API_BASE", "https://api.example.com")
ap = argparse.ArgumentParser(); ap.add_argument("url"); ap.add_argument("--lang", default="en"); ap.add_argument("--out", default="subs")
a = ap.parse_args(); os.makedirs(a.out, exist_ok=True)
vid = re.search(r"\d{19}", a.url).group(0)
for fmt in ("srt", "vtt"):
    r = requests.get(f"{API}/api/v1/tiktok/transcript", params={"url": a.url, "lang": a.lang, "format": fmt},
                     headers={"Authorization": f"Bearer {os.environ['TTA_API_KEY']}"}, timeout=60)
    if r.status_code != 200:
        e = r.json()["error"]; sys.exit(f"{fmt}: {e['code']}: {e['message']}")
    path = os.path.join(a.out, f"{vid}.{a.lang}.{fmt}")
    open(path, "w", encoding="utf-8", newline="\n").write(r.text)
    cues = len(re.findall(r"-->", r.text))
    ok = r.text.startswith("WEBVTT") if fmt == "vtt" else r.text.startswith("1\n")
    print(f"wrote {path}: {cues} cues, header ok={ok}")

Captured runs

English (mock)
wrote subs/7000000000000000001.en.srt: 5 cues, header ok=True
wrote subs/7000000000000000001.en.vtt: 5 cues, header ok=True
Spanish, which the fixture offers (mock)
wrote subs/7000000000000000001.es.srt: 5 cues, header ok=True
wrote subs/7000000000000000001.es.vtt: 5 cues, header ok=True
French, which it does not (mock)
srt: language_unavailable: Languages available: eng-US, spa-ES

What can go wrong

  • The language is not available: you get language_unavailable and the message lists the tracks that are.
  • Two requests mean two successful calls and two charges; if you only need one format, ask for one.
  • Automatic captions can be wrong on names. Proofread before you publish subtitles.

Get an API key to run it against the real service. Run against the local mock in tools/mock-api, which follows the assumed contract on these pages. It is not the real API, and the output is captured from that mock.

Frequently asked questions

Why UTF-8?

Subtitles often contain accents and emoji. UTF-8 is what most editors and web players expect.

Can I make one request and convert locally?

Yes. Ask for JSON and build the files from the segments to save a call.

Does it burn subtitles into the video?

No. It writes the text files only.

Need this data in your app?

Get API key
Get API keyDocs