Frameskim Apify Store

YouTube transcript API

Get a YouTube transcript from Python, Node or curl

POST the URL of a public YouTube video and get its transcript back as JSON: one segment per line with its start and end in seconds, and the full text. It needs an Apify API token, not a YouTube API key.

$0.01 per transcript. Failed videos are not charged.

Input and output

Input
{
  "urls": ["https://youtu.be/4czjS9h4Fpg"],
  "lang": "en"
}

Up to 100 video, channel or playlist URLs per run, 100 videos in total. lang defaults to en and falls back to the video’s original language.

Output: real item, one per video
{
  "videoId": "4czjS9h4Fpg",
  "title": "Perseverance Rover’s Descent and Touchdown on Mars (Official NASA Video)",
  "lang": "en",
  "segments": [
    { "start": 0.4, "end": 3.28, "text": "We are starting the straighten up and fly right maneuver," },
    { "start": 3.28, "end": 7.36, "text": "where the spacecraft will jettison the entry balance masses in preparation for" },
    { "start": 7.36, "end": 14.16, "text": "parachute deploy and to roll over to give the radar a better look at the ground." },
    ...
  ],
  "text": "We are starting the straighten up and fly right maneuver, where the spacecraft will jettison the...",
  "frameskimUrl": "https://apify.com/emttn/frameskim"
}

The real transcript of NASA’s Perseverance descent video (courtesy NASA/JPL-Caltech): 30 segments, the first three shown, and the text shortened.

The same call in three languages

curl
curl -X POST "https://api.apify.com/v2/acts/emttn~youtube-transcript/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://youtu.be/4czjS9h4Fpg"]}'
Python
import os, requests

res = requests.post(
    "https://api.apify.com/v2/acts/emttn~youtube-transcript/run-sync-get-dataset-items",
    headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
    json={"urls": ["https://youtu.be/4czjS9h4Fpg"]},
    timeout=300,
)
item = res.json()[0]
print(item["segments"][0])
Node
const res = await fetch("https://api.apify.com/v2/acts/emttn~youtube-transcript/run-sync-get-dataset-items", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ urls: ["https://youtu.be/4czjS9h4Fpg"] }),
});
const [item] = await res.json();
console.log(item.segments[0]);

From a cloud server or a CI runner

The request runs on Apify, which reaches YouTube through its datacenter and residential proxies, not through your server’s IP address. A video YouTube still blocks comes back as an item with error and is not charged.

Limits

  • Videos need captions: it does not transcribe audio.
  • Public videos, channels and playlists, up to 100 videos per run; each channel or playlist adds up to maxVideos of its videos (20 by default). Searches are refused before anything runs, with nothing charged.
  • $0.01 per transcript delivered, pay per event on Apify, never above the spending limit you set.