# YouTube Transcripts API - Original Spoken Language (`neonroobz/youtube-transcripts`) Actor

YouTube transcripts in the language actually spoken: right on 44 of 45 videos in our published test, none wrong, vs 31 for the top 3 Store tools. Subtitles and captions with timestamps from videos, Shorts, playlists and channels. $2 per 1,000; you pay only for correct ones.

- **URL**: https://apify.com/neonroobz/youtube-transcripts.md
- **Developed by:** [nnrbzz](https://apify.com/neonroobz) (community)
- **Categories:** Videos, AI, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Transcript & Subtitle API - Original Language

Get **YouTube transcripts, subtitles and captions in the language actually spoken**, from **videos, Shorts, playlists and whole channels**, with timestamps and LLM-ready chunks. Other tools return the first caption track, often a translation, or need the language named in advance; this one finds the spoken language itself, checks it against the text, and charges only for correct transcripts. Paste one YouTube link and click Start: at **$2 per 1,000**, Apify's free plan's $5 monthly credit covers **2,500 transcripts**.

### What does it do?

- **Returns the spoken language, no language code needed.** In our published test it was right on 44 of 45 captioned videos and wrong on none (the 45th came back free as "language unknown"). The top 3 Store tools each got 31. See [the comparison](#which-tools-return-the-right-language-measured).
- **Checks every transcript's language against its text before you're charged.** When YouTube's auto-caption label is wrong (English speech labelled Dutch, say), you get the language actually spoken, flagged as corrected.
- **Charges only for correct transcripts.** A video with no captions, one that fails, or one whose spoken language can't be named still gets a row saying why. That row is free.
- **Takes videos, Shorts, playlists and channels in bulk,** mixed in one run.
- **Gives timestamps and ~300-word chunks** ready to embed, quote or feed to an LLM.
- **Pro adds an English translation and a 5-point summary** with 3 topics.

It works through the Apify API, on a schedule, in Claude, Cursor and ChatGPT through Apify's MCP server, and in n8n, Make and Zapier.

### Use cases

- **RAG and knowledge bases:** load a whole channel as timestamped chunks you can cite.
- **Multilingual content research:** compare what Spanish, Japanese or Hindi creators say, in their own words, not a machine translation.
- **Repurposing videos:** turn talks and podcasts into blog posts, newsletters and social posts.
- **Competitor and brand monitoring:** read every new upload from the channels you follow.
- **Language datasets:** collect captions labelled with a language that has been checked against the text.
- **AI agents that need clean transcripts:** a stable `status` and `error_code` on every row, so an agent knows what happened.

### What data do you get?

| | Data | Fields |
|---|---|---|
| 📝 | Full transcript text | `text`, `word_count`, `char_count` |
| ⏱️ | Caption lines with start time and duration | `segments` |
| 🧩 | ~300-word chunks with start and end times | `chunks` |
| 🗣️ | Spoken language and caption language | `spoken_language`, `caption_language`, `caption_language_name` |
| ✅ | Language check against the text | `language_check`, `language_detected`, `language_corrected`, `language_label_youtube` |
| 🤖 | Auto-generated or translated captions | `is_auto_generated`, `is_translated`, `language_signal` |
| 🌐 | Every caption track on the video | `available_languages` |
| 🎬 | Video details | `video_id`, `url`, `title`, `channel`, `channel_id`, `duration_s` |
| 🚦 | Outcome and charge | `status`, `error_code`, `error`, `charged_event`, `attempts_used`, `source` |
| ✨ | Pro: English translation and summary | `translation_en`, `summary`, `pro_status`, `model_cost_usd` |

### How to get YouTube transcripts

1. [Create a free Apify account](https://console.apify.com/sign-up).
2. Open this actor and click **Try for free**.
3. Paste video, Shorts, playlist or channel links (or video IDs).
4. Click **Start**.
5. Download the results as JSON, CSV or Excel, or get them through the API.

An empty input runs one example video, so you can see a real row first.

### How much does it cost to get YouTube transcripts?

| Price | Per 1,000 videos | Each | Charged when |
|---|---|---|---|
| Transcript | **$2 per 1,000** | $0.002 | the transcript is delivered |
| Transcript + Pro | **$12 per 1,000** | $0.012 | Pro is on and the English translation and summary are both delivered |
| Failed, no captions, language unknown | **free** | $0 | never |
| Run start | **free** | $0 | never: you pay nothing for runs where no transcript is delivered |

**Free plan:** Apify's $5 monthly credit covers 2,500 transcripts, or about 415 with Pro.

**Examples:**

- A 100-video playlist: $0.20.
- 1,000 videos from 10 channels: $2 (with Pro: $12).
- 10,000 videos: $20.

### Input

**One video** (the prefilled example):

```json
{ "videos": ["https://www.youtube.com/watch?v=aircAruvnKk"] }
```

**A playlist:**

```json
{ "playlists": ["https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi"], "maxVideosPerSource": 50 }
```

**A channel's newest uploads:**

```json
{ "channels": ["https://www.youtube.com/@3blue1brown"], "maxVideosPerSource": 20 }
```

| Field | Default | What it does |
|---|---|---|
| `videos` | — | Watch, `youtu.be`, `shorts`, `embed`, `live` and mobile URLs, or 11-character IDs. A video given twice is fetched and charged once. |
| `playlists` | `[]` | Any URL with `list=`, or a playlist ID. |
| `channels` | `[]` | `@handle`, `/channel/UC…`, `/c/…`, `/user/…`, or a `UC…` ID. Newest uploads first, including Shorts and past live streams. |
| `maxVideosPerSource` | 100 | Videos per playlist or channel, up to 1,000. |
| `originalLanguageOnly` | `true` | Strict mode: when YouTube gives no signal for the spoken language, or has no captions in it, you get a free error row, not a guess. Turn it off to get the best other track. |
| `preferredLanguage` | empty | Empty: the spoken language. A code such as `es`, `ja` or `pt-BR`: that language instead. Human captions come first, then auto-generated ones, then YouTube's own translation (flagged `is_translated: true`). If none exists, you get a free `language_unavailable` row. |
| `pro` | `false` | English translation and summary (see [Pro](#pro)). |
| `includeSegments` | `true` | Each caption line with its start and duration. Turning it off roughly halves the row size, and `text` and `chunks` stay. |
| `maxAttempts` | 10 | Attempts per video, each on a fresh proxy IP. |
| `concurrency` | 10 | Videos fetched in parallel. |

An empty input (`{}`) runs the example video above, charged as one transcript when delivered.

If YouTube's playlist listing can't be read, the actor falls back to the public feed, which lists only the newest 15 videos. The run log and the `OUTPUT` record say how many videos each source gave.

### Output

One dataset row per video. A Korean video with human Chinese, English, Japanese and Spanish translations (the Store leader returns Chinese here):

```json
{
  "video_id": "1qOJvWakMz0",
  "url": "https://www.youtube.com/watch?v=1qOJvWakMz0",
  "title": "…",
  "channel": "BANGTANTV",
  "channel_id": "UC…",
  "duration_s": 1307,
  "status": "ok",
  "error_code": null,
  "spoken_language": "ko",
  "caption_language": "ko",
  "caption_language_name": "Korean",
  "is_auto_generated": false,
  "is_translated": false,
  "language_signal": "single_auto_track",
  "language_check": "verified",
  "language_detected": "ko",
  "language_corrected": false,
  "language_label_youtube": null,
  "available_languages": ["zh", "en", "ja", "ko", "ko:auto", "es"],
  "word_count": 1758,
  "text": "…the whole transcript, once…",
  "segments": [{ "start": 0.4, "dur": 3.1, "text": "…" }],
  "chunks": [{ "start": 0.4, "end": 131.9, "text": "…about 300 words…" }],
  "attempts_used": 1,
  "source": null,
  "error": null,
  "charged_event": "transcript"
}
```

`char_count` (left out above) follows `word_count`.

A row that isn't delivered is free, and says why:

```json
{ "video_id": "…", "status": "no_captions", "error_code": "no_captions", "text": null, "chunks": [], "error": "this video has no captions", "charged_event": null }
```

#### Pro

Set `"pro": true`. Each delivered row also gets:

```json
{
  "pro_status": "ok",
  "translation_en": "…English translation…",
  "translation_note": null,
  "summary": { "bullets": ["…", "…", "…", "…", "…"], "topics": ["…", "…", "…"] },
  "models": { "translation": "deepseek/deepseek-v4-flash", "summary": "anthropic/claude-haiku-5.5" },
  "model_cost_usd": 0.0029,
  "charged_event": "transcript-pro"
}
```

- **English transcripts get no translation call.** This covers a video spoken in English, and one you asked for in English with `preferredLanguage`. `translation_en` is `null`, `translation_note` says why, and the summary is still made.
- **Long videos:** transcripts over 10,000 words (Chinese and Japanese: characters ÷ 2), roughly over an hour of speech, get no translation or summary. You get the transcript at the core price ($0.002), with `pro_status: "skipped_too_long"` and `pro_error_code: "too_long_for_pro"`.
- **If a model fails:** you get the transcript at the core price, with `pro_status: "failed"`, `pro_error_code: "model_error"`, and any part that worked.
- **The models were chosen in blind quality tests.** DeepSeek V4 Flash matched the best translator we tested, at about half the cost. Claude Haiku 5.5 was the only summariser with no factual errors.

#### Field notes

- `status`: `ok`, `no_captions` or `error`. `error_code` is `null` exactly when `status` is `ok`.
- `spoken_language`: the language spoken in the video, as YouTube signals it. `null` when there is no signal (only possible with strict mode off).
- `caption_language`: the language of the text you got. It equals `spoken_language` unless you set `preferredLanguage`.
- `is_auto_generated`: YouTube's speech recognition rather than human captions. `is_translated`: YouTube machine-translated the text (only with `preferredLanguage`).
- `language_signal`: what named the language. `original_audio`: the audio track marked original. `single_auto_track`: the one speech-recognition track. `only_caption_language`: every track is in one language. `preferred_language`: you asked for it. With strict mode off, `default_track` (YouTube's default track for English-language viewers) and `first_track` mean there was no signal: they are guesses.
- `language_check`: the text's language checked against its label before charging.
  - `verified`: they agree.
  - `corrected`: an auto-generated track whose text is another language; `spoken_language` and `caption_language` give the language of the text, `language_label_youtube` YouTube's label.
  - `mismatch`: a human track whose text is another language, delivered only because `preferredLanguage` asked for that label (otherwise it is a free `language_mismatch` row).
  - `unchecked`: too short to judge (under about 200 letters, or 60 Chinese, Japanese or Korean characters), or a language the check doesn't cover.
- `language_detected`: the language the check read in the text (`null` when unchecked). `language_corrected`: `true` when the label was corrected.
- `available_languages`: every caption track, sorted by code. Auto-generated ones end in `:auto`.
- `chunks`: whole caption lines grouped into about 300 words, with start and end times. Chinese and Japanese characters count as half a word; for those, `char_count` is the better size measure.
- `source`: the playlist or channel the video came from.

### Which tools return the right language (measured)

On 23 Oct 2026 we ran the top 3 transcript tools in the Store, two transcript APIs outside Apify, and our engine on the same 50 videos. 45 have captions and 5 have none. Each tool ran with its default input, without naming a language.

**Apify Store:**

| | Right spoken language, of 45 captioned | Billed for empty or wrong results |
|---|---|---|
| Store leader (`starvibe/youtube-video-transcript`) | 31 | 19 of 50 |
| No. 2 (`johnvc/YoutubeTranscripts`, `languages: ["en"]`) | 31 | 2 |
| No. 3 (`pintostudio/youtube-transcript-scraper`, `targetLanguage: "en"`) | 31 | 13 (10 of them machine translations) |
| **This actor's engine** | **43** at 5 attempts per video; **45** in each of two runs at 10 attempts (the default) | **0**: the 5 no-caption videos were reported free |

**Outside Apify** (called with no language, as a typical buyer would):

| | Right spoken language, of 45 captioned | Wrong language delivered | No answer |
|---|---|---|---|
| Supadata (`mode=native`) | 41 | 4 | 0 |
| TranscriptAPI | 39 | 2 | 4 timeouts |
| **This actor on Apify** | **44** | **0** | 1, free as "language unknown" |

- **This actor on Apify, 23 Oct 2026:** 44 of 45 in the right language and 5 of 5 no-caption videos reported free. The 45th came back free as `original_language_unknown`, because YouTube gave no reliable signal for it (see [How we measured](#how-we-measured)).
- **Delivery at volume:** 98.6% of 498 videos were delivered in one run at 10 videos in parallel.

How the others miss, in our published test:

- **The leader takes the first human track in YouTube's list.** That list is sorted for the viewer's locale, not by the video's language. So an English TED talk with an Arabic translation comes back in Arabic, and an auto-dubbed video comes back as its first dub.
- **No. 2 needs the language named in advance.** On its default (English), non-English videos come back empty.
- **No. 3 machine-translates everything to English** and does not say so.
- **Supadata** returned Arabic for 2 English videos and for 1 auto-dubbed Spanish one, and English for the Korean video above. It also returned 34 words for one of the 5 no-caption videos.
- **TranscriptAPI** returned Galician for a Spanish video and English for the Korean one, and timed out on 4 small English channels.

### Error codes

Every row with an error code is free.

| `error_code` | Meaning | Retried? |
|---|---|---|
| `no_captions` | The video has no captions. We don't transcribe audio. | no |
| `original_language_unknown` | Strict mode: YouTube gives no signal for the spoken language. | no |
| `original_language_unavailable` | Strict mode: the spoken language is known (in `spoken_language`) but has no captions. | no |
| `language_unavailable` | No captions in `preferredLanguage`, and no YouTube translation into it; or YouTube's auto-generated track in that language turned out to be in another language (`language_label_youtube` gives YouTube's label, `language_detected` the language of the text). | no |
| `language_mismatch` | A human caption track whose text is in another language than its label (likely a translation uploaded under the wrong label). Ask for that label with `preferredLanguage` to get it anyway. | no |
| `private` | The video is private. | no |
| `age_restricted` | The video needs a signed-in adult account. | no |
| `members_only` | Channel members only. | no |
| `unavailable` | Removed, blocked in the proxy's country, or otherwise not playable. | when YouTube says unplayable |
| `bot_check` | YouTube asked every attempt's IP to prove it isn't a bot. | yes, up to `maxAttempts` |
| `network_error` | The connection failed on every attempt. | yes |
| `caption_fetch_failed` | The captions were listed but didn't download on any attempt. | yes |
| `invalid_input` | Not a YouTube video, playlist or channel. | no |
| `source_unavailable` | A playlist or channel that couldn't be read. | yes, inside the source read |
| `internal_error` | An unexpected error on our side. Please open an issue. | no |

### FAQ

#### How much does it cost?

$2 per 1,000 transcripts ($0.002 each), $12 per 1,000 with Pro. Apify's free plan gives $5 of credit every month: 2,500 transcripts, or about 415 with Pro. Failed videos, videos with no captions and run starts are free. See [the pricing table](#how-much-does-it-cost-to-get-youtube-transcripts).

#### Can I use it with integrations?

Yes. Apify connects to n8n, Make, Zapier, Google Sheets, Slack, Airbyte and more, and can send the dataset to them when a run finishes. You can also run it on a schedule, for example to read a channel's new uploads every day.

#### Can I use it with the API?

Yes. To run it and get the rows in one call, `POST` your input to `https://api.apify.com/v2/acts/neonroobz~youtube-transcripts/run-sync-get-dataset-items?token=<YOUR_TOKEN>`. The Apify clients for Python (`apify-client`) and JavaScript (`apify-client`) do the same: `client.actor("neonroobz/youtube-transcripts").call(...)` with your input. Set `includeSegments: false` to save tokens: `text` and the timed `chunks` stay.

#### Can I use it through an MCP server?

Yes. Add `https://mcp.apify.com?tools=neonroobz/youtube-transcripts` to Claude, Cursor, ChatGPT or any MCP client, then ask, for example, "get the transcripts of the last 10 videos on @3blue1brown". Pricing is pay-per-event only, every input has a working default, and every row carries a stable `status` and `error_code` an agent can act on.

#### Is it legal to scrape YouTube transcripts?

This actor reads only captions that YouTube shows publicly to any logged-out viewer. It doesn't sign in, and it doesn't read private, members-only or age-restricted videos. It stores no personal data. Scraping publicly available data is legal as long as you respect copyright and personal-data rules such as the GDPR: transcripts are the creators' work, so check how you may reuse them. If you're unsure, ask a lawyer. Apify's blog has more on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Which language do I get?

By default, the language spoken in the video. YouTube's own signals name it:

1. the audio track marked original (on auto-dubbed videos);
2. otherwise the language of the speech-recognition track;
3. otherwise the only language the captions are in.

If there is a human caption track in that language, you get it, because it is usually cleaner than the auto-generated one. With strict mode on (the default), a video with none of these signals gives a free error row.

YouTube's *default* caption track is not one of the signals. We measured it: on the same TED talk it is English for an English-language viewer, Spanish for a Spanish one and Arabic for an Arabic one, and the order of the track list changes the same way. A video with only human captions in several languages and no speech-recognition track (typical of TED talks) therefore gets `original_language_unknown` in strict mode. With strict mode off, you get the default track for English-language viewers, labelled `default_track` with `spoken_language: null`. Set `preferredLanguage` if you want a specific language instead.

#### Why does a row say `language_corrected: true`?

YouTube sometimes labels English speech by a guest's accent or by the topic: a Computerphile interview with a Dutch guest speaking English came labelled Dutch, and a DW News report in English on German politics came labelled German. The words in the auto-captions are what was said, so you get them, labelled as the language they are in (`en`), with YouTube's label kept in `language_label_youtube`. The charge is the normal one: the text is right.

If you asked for a language with `preferredLanguage` and the auto track labelled with it is really another language, you get a free `language_unavailable` row instead. A *human* track whose text doesn't match its label is not delivered (a free `language_mismatch` row), because that is usually a translation, not the spoken language.

#### What if a video has no captions?

You get a free `no_captions` row. We return the captions YouTube has, human or auto-generated. We don't transcribe audio.

#### What about long videos and Pro?

Pro covers transcripts up to 10,000 words. Longer ones are delivered and charged at the core price, without the translation and summary.

#### What does the run summary hold?

The `OUTPUT` record in the key-value store holds:

- counts by status and by error code;
- `delivery_rate`: delivered ÷ (delivered + videos that failed after fetching);
- attempts per video;
- which language signal was used;
- `language_check`: how many transcripts were verified, corrected, refused as a mismatch, or unchecked;
- events charged and Pro model cost;
- each playlist and channel and how many videos it gave;
- `not_processed`: videos not reached because of your spending limit.

#### How often is it updated?

YouTube changes its pages without notice. Each release is run against the 50-video test set, and we aim to fix a break within a day of finding it.

#### Is anything stored?

No. Nothing is kept between runs.

### How we measured

- **Test set:** 50 public videos, fixed in advance: English talks with many human translations; small English channels with auto-captions only; Spanish, German, Japanese, Portuguese, Hindi and Korean originals; long videos, Shorts and auto-dubbed videos; 5 videos with no captions.
- **Reference:** each video's spoken language, set from YouTube's caption and audio tracks by the same rule our engine uses, then checked by eye against the channel and title language for all 50.
- **Scoring:** a result is right when the transcript's language is the spoken one, and billed when the tool charged for that video.
- **Runs:**
  - The Store tools ran on Apify with a typical buyer's default input: No. 2 with its default `languages: ["en"]`, No. 3 with its required `targetLanguage` at its default `"en"`.
  - Supadata ran with `mode=native` (captions only) and TranscriptAPI with no language, both on 23 Oct 2026.
  - Our engine ran from Apify datacenter proxies, at 5 attempts per video and then twice at 10.
  - Delivery was measured on a separate 498-video run: the 50 test videos plus recent uploads from 35 large channels.
- **Strict mode** was added after the engine runs. It changes a result only when YouTube gives none of the 3 language signals in the FAQ. On the test set that is one video, an English TED talk with 7 human caption tracks and no speech-recognition track. It counted as right in the engine runs only because YouTube's default caption track was English, and that track follows the viewer's locale (all our requests are sent as an English-language viewer). Strict mode now returns it as a free `original_language_unknown` row.
- **Language check:** an offline language detector (franc 6.2.0, trigrams) read the first 3,000 characters of the 524 transcripts delivered in the 498-video and 50-video runs. 514 agreed with their label. 5 were close dialects of the label (Scots for English, Magahi or Bhojpuri for Hindi), 3 were too short to judge, and 2 were real mislabels: English speech on YouTube auto-caption tracks labelled Dutch and German. With dialects counted as their language and a minimum length, the check raises 0 false alarms on those 524 and catches both mislabels. It now runs on every transcript before charging.

### Limits

- **Captions only, public videos only.** No audio transcription.
- **"Original language" is YouTube's own signal.** Auto-captions keep their own mistakes, such as misheard names and missing punctuation. The translation and summary work from that text.
- **Datacenter IPs are sometimes asked to prove they aren't bots.** The run summary reports attempts per video, so you can see when this happens more often.

### Feedback

A video came back wrong, or something broke? Open an issue in the **Issues** tab with the video URL. We aim to fix a break within a day of finding it.

# Actor input Schema

## `videos` (type: `array`):

Video URLs (watch, youtu.be, shorts, embed, live) or 11-character IDs. Duplicates are fetched and charged once.

## `playlists` (type: `array`):

Playlist URLs or IDs. Each gives up to maxVideosPerSource videos.

## `channels` (type: `array`):

Channel URLs, @handles or UC... IDs. Each gives its newest uploads, up to maxVideosPerSource.

## `maxVideosPerSource` (type: `integer`):

Videos taken from each playlist or channel (newest first for channels). Default 100, maximum 1,000.

## `originalLanguageOnly` (type: `boolean`):

On: when YouTube gives no signal for the spoken language, or has no captions in it, the row is a free error (original_language_unknown / original_language_unavailable), never a guess. Off: return the best other track.

## `preferredLanguage` (type: `string`):

Leave empty for the spoken language. A code like es, ja or pt-BR returns that language: human captions first, then auto, then YouTube's translation (is_translated: true). Not available: free language_unavailable row.

## `pro` (type: `boolean`):

Adds an English translation (skipped when the transcript is English) and a 5-bullet summary with 3 topics. Charged as transcript-pro instead of transcript, only when both are present. Transcripts over 10,000 words get no add-ons and are charged as transcript.

## `includeSegments` (type: `boolean`):

Each caption line with start and duration in seconds. Off keeps text and ~300-word timed chunks and roughly halves the row size.

## `maxAttempts` (type: `integer`):

Each attempt uses a fresh proxy IP; retried on bot checks and network errors. Failed videos are free.

## `concurrency` (type: `integer`):

Videos fetched in parallel.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "playlists": [],
  "channels": [],
  "maxVideosPerSource": 100,
  "originalLanguageOnly": true,
  "pro": false,
  "includeSegments": true,
  "maxAttempts": 10,
  "concurrency": 10
}
```

# Actor output Schema

## `transcripts` (type: `string`):

Transcripts: one row per video, including free rows for videos with no captions, failures and language-unknown, each with error_code.

## `summary` (type: `string`):

Run summary: counts by status and error code, delivery rate, language checks, attempts, model cost.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "videos": [
        "https://www.youtube.com/watch?v=aircAruvnKk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neonroobz/youtube-transcripts").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "videos": ["https://www.youtube.com/watch?v=aircAruvnKk"] }

# Run the Actor and wait for it to finish
run = client.actor("neonroobz/youtube-transcripts").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "videos": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ]
}' |
apify call neonroobz/youtube-transcripts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neonroobz/youtube-transcripts"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/pYLvSLNCg8d1OEvIP/builds/saGXxpVYwIqZnDULb/openapi.json
