# YouTube Transcript & Subtitles Scraper API (`ryumoon-data/youtube-transcript-scraper`) Actor

Scrape YouTube transcripts, subtitles and captions in bulk from videos, Shorts, channels and playlists. Clean text plus timestamps. Works from MCP clients such as Claude, Cursor and ChatGPT. No YouTube API key. $3 per 1,000 transcripts; videos with no captions are free.

- **URL**: https://apify.com/ryumoon-data/youtube-transcript-scraper.md
- **Developed by:** [Ryu Moon](https://apify.com/ryumoon-data) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 transcripts

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 & Subtitles Scraper, Bulk

**Turn YouTube videos, playlists and whole channels into clean transcripts with timestamps, for $3 per 1,000 videos.**

#### Who it's for

Content creators, marketers, researchers, and AI builders who need the spoken words from YouTube as text, in bulk.

#### What people use it for

- ✍️ **Content repurposing.** Turn a talk or tutorial into a blog post, newsletter or social thread.
- 📺 **Playlist and channel transcripts.** Get a whole course playlist or a channel's latest videos in one run.
- 🧠 **AI summaries and RAG.** Feed transcripts to ChatGPT or Claude, or index them with timestamps so answers can cite the exact moment.
- 🌍 **Other-language subtitles.** Request `es`, `de`, `fr` and so on, with a fallback to auto-captions or the original language.

#### Real sample output

From a real run on `https://www.youtube.com/watch?v=aircAruvnKk` (shortened):

````json
{
  "videoId": "aircAruvnKk",
    "title": "But what is a neural network? | Deep learning chapter 1",
      "channelName": "3Blue1Brown",
        "duration": "18:40",
          "language": "en",
            "isAutoGenerated": false,
              "wordCount": 3357,
                "segmentCount": 286,
                  "transcript": "This is a 3. It's sloppily written and rendered at an extremely low resolution of 28x28 pixels, but your brain has no trouble recognizing it as a 3. And I want you to take a moment to appreciate how c…",
                    "segments": [
                        {
                              "start": 4.22,
                                    "duration": 1.18,
                                          "end": 5.4,
                                                "text": "This is a 3."
                                                    },
                                                        {
                                                              "start": 6.06,
                                                                    "duration": 4.653,
                                                                          "end": 10.713,
                                                                                "text": "It's sloppily written and rendered at an extremely low resolution of 28x28 pixels,"
                                                                                    }
                                                                                      ]
                                                                                      }
                                                                                      ```

                                                                                      ### What it costs (real prices)
                                                                                      Prices are pay per event: **$0.003 per transcript saved** and a **$0.005** start fee per run. Videos with no captions, private videos and bad links are free.

                                                                                      | Job | Calculation | USD | GBP* |
                                                                                      |---|---|---|---|
                                                                                      | 10-video playlist | 10 × $0.003 + $0.005 | $0.035 | £0.03 |
                                                                                      | 100 videos | 100 × $0.003 + $0.005 | $0.305 | £0.23 |
                                                                                      | 1,000 videos | 1,000 × $0.003 + $0.005 | $3.005 | £2.25 |

                                                                                      *GBP at 1 USD = £0.74711 (ECB rate, 6 Nov 2026). Apify bills in USD. The start fee is charged per GB of run memory; the default is 256 MB.


                                                                                      ## Integrations

                                                                                      All recipes below use Apify's own official integrations. You need a free Apify account.

                                                                                      - **Zapier.** Add Apify as the action in a Zap, pick **Run Actor** (or **Run Task** for a saved example), choose `ryumoon-data/youtube-transcript-scraper` and paste the input JSON. Then add **Fetch dataset items** to pass the results to Google Sheets, Slack, Notion and so on. Synchronous runs in Zapier time out after 30 seconds, so for big batches use the **Finished Actor run** trigger in a second Zap. [Apify docs: Zapier](https://docs.apify.com/platform/integrations/zapier)
                                                                                      - **Make.** Add the Apify module **Run an Actor** with "Run synchronously" set to Yes, then **Get Dataset Items** using the run's default dataset ID, then e.g. Google Sheets "Bulk Add Rows". For long runs, use the **Watch Actor Runs** trigger instead. [Apify docs: Make](https://docs.apify.com/platform/integrations/make)
                                                                                      - **n8n.** Install the Apify node (`@apify/n8n-nodes-apify` from Community Nodes on self-hosted, or search "Apify" in the nodes panel on n8n Cloud). Add an Apify API key or OAuth2 (Cloud) credential, then use it as an action to run this Actor, or as the **On new Apify Event** trigger to process results when a run finishes. [Apify docs: n8n](https://docs.apify.com/platform/integrations/n8n)
                                                                                      - **MCP (Claude, ChatGPT and other AI agents).** Add Apify's hosted MCP server to your client. To load only this Actor, use `https://mcp.apify.com?tools=ryumoon-data/youtube-transcript-scraper`. The first time you connect, your browser opens so you can sign in to Apify. Alternatively, send an `Authorization: Bearer <APIFY_TOKEN>` header:
                                                                                        ```json
                                                                                          { "mcpServers": { "apify": { "url": "https://mcp.apify.com?tools=ryumoon-data/youtube-transcript-scraper" } } }
                                                                                            ```
                                                                                              Your assistant can then run it from a prompt like *"Get the transcripts of the first 3 videos in this YouTube playlist"*. [Apify docs: MCP server](https://docs.apify.com/platform/integrations/mcp)

                                                                                              ---

                                                                                              Get the **transcript of any YouTube video** as clean text plus **timestamped segments**, in bulk. Paste video links, a whole **channel** or a **playlist**, choose your language, and download YouTube **subtitles and captions** as JSON, CSV, Excel, XML or HTML (Apify's dataset export formats). Built for AI and LLM pipelines, RAG, content repurposing, SEO and research.

                                                                                              **$3 per 1,000 transcripts.** Videos without captions, private videos and bad links are free. No YouTube API key, no login, no cookies.

                                                                                              ## Why this YouTube transcript scraper?

                                                                                              - ✅ **Runs don't fail on bad input.** A broken link, a private video or a video with no captions is skipped with a clear `status` and reason. The rest of your batch still finishes.
                                                                                              - 🌍 **Language choice with fallback.** List the languages you want in order (`en`, `en-GB`, `es`...). It uses human-made subtitles first, then auto-generated captions, then (optionally) the video's original language.
                                                                                              - ⏱️ **Plain text *and* timestamps.** You get a readable `transcript` with paragraphs, a `segments` array (start, end and duration in seconds), and an optional `[m:ss]` timestamped text.
                                                                                              - 📺 **Bulk mode for channels, Shorts, live streams and playlists.** Give it `@channel`, `/shorts`, `/streams` or a playlist URL and set how many videos to take.
                                                                                              - 🏷️ **Video metadata included:** title, channel name and ID, duration, view count, thumbnail and the full list of caption languages.
                                                                                              - ⚡ **No browser.** It uses plain HTTP requests, with no headless Chrome, so you only pay the per-transcript price plus the start fee.

                                                                                              ## How to use it

                                                                                              1. Paste one or more **YouTube video URLs or IDs** (watch, youtu.be, Shorts, live and embed links all work).
                                                                                              2. Optionally add **channel or playlist URLs** and set **Max videos per channel or playlist**.
                                                                                              3. Set **Preferred languages** (e.g. `en`). Leave it empty to get each video's original language.
                                                                                              4. Click **Start**, then export the dataset or call it from the Apify API or any of Apify's official integrations (Make, Zapier, n8n, LangChain, MCP).

                                                                                              ### Example input
                                                                                              ```json
                                                                                              {
                                                                                                "videoUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw", "dQw4w9WgXcQ"],
                                                                                                  "channelOrPlaylistUrls": ["https://www.youtube.com/@veritasium"],
                                                                                                    "maxVideosPerChannel": 10,
                                                                                                      "languages": ["en"],
                                                                                                        "includeTimestampedText": true
                                                                                                        }
                                                                                                        ```

                                                                                                        ### Example output (one item per video)
                                                                                                        ```json
                                                                                                        {
                                                                                                          "status": "success",
                                                                                                            "videoId": "jNQXAC9IVRw",
                                                                                                              "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
                                                                                                                "title": "Me at the zoo",
                                                                                                                  "channelName": "jawed",
                                                                                                                    "channelId": "UC4QobU6STFB0P71PMvOGN5A",
                                                                                                                      "durationSeconds": 19,
                                                                                                                        "duration": "0:19",
                                                                                                                          "viewCount": 380000000,
                                                                                                                            "language": "en",
                                                                                                                              "languageName": "English",
                                                                                                                                "isAutoGenerated": false,
                                                                                                                                  "availableLanguages": [{ "code": "en", "name": "English", "autoGenerated": false }, { "code": "de", "name": "German", "autoGenerated": false }],
                                                                                                                                    "transcript": "All right, so here we are, in front of the elephants...",
                                                                                                                                      "wordCount": 39,
                                                                                                                                        "segments": [{ "start": 1.2, "duration": 2.16, "end": 3.36, "text": "All right, so here we are, in front of the" }],
                                                                                                                                          "timestampedTranscript": "[0:01] All right, so here we are, in front of the\n..."
                                                                                                                                          }
                                                                                                                                          ```

                                                                                                                                          ### Status values
                                                                                                                                          | status | meaning | charged? |
                                                                                                                                          |---|---|---|
                                                                                                                                          | `success` | Transcript saved | yes |
                                                                                                                                          | `no_transcript` | The video has no captions (or none in your languages with fallback off) | no |
                                                                                                                                          | `video_unavailable` | Private, deleted, region-locked or age-restricted video | no |
                                                                                                                                          | `invalid_input` | Not a YouTube video, channel or playlist link | no |
                                                                                                                                          | `blocked` / `error` | YouTube refused after several retries. Run again or add a proxy | no |

                                                                                                                                          A run summary (counts plus every skipped input with its reason) is saved as `SUMMARY` in the key-value store.


                                                                                                                                          ## Run it from code (Python)
                                                                                                                                          `pip install apify-client`, then:
                                                                                                                                          ```python
                                                                                                                                          from apify_client import ApifyClient

                                                                                                                                          client = ApifyClient("YOUR_APIFY_TOKEN")
                                                                                                                                          run = client.actor("ryumoon-data/youtube-transcript-scraper").call(run_input={
                                                                                                                                              "channelOrPlaylistUrls": ["https://www.youtube.com/@TED"],
                                                                                                                                                  "maxVideosPerChannel": 20,
                                                                                                                                                      "languages": ["en"],
                                                                                                                                                      })
                                                                                                                                                      for item in client.dataset(run.default_dataset_id).iterate_items():
                                                                                                                                                          if item["status"] == "success":
                                                                                                                                                                  print(item["title"], item["wordCount"])
                                                                                                                                                                  ```
                                                                                                                                                                  Node.js: `npm i apify-client`, then `await client.actor('ryumoon-data/youtube-transcript-scraper').call(input)` and `client.dataset(run.defaultDatasetId).listItems()`.

                                                                                                                                                                  ## Whole channel into one file for ChatGPT or Claude
                                                                                                                                                                  Run with `includeSegments: false` and `includeTimestampedText: false` to keep items small, then join the `transcript` fields with the `title` as a heading. One plain-text file per channel uploads cleanly to ChatGPT, Claude Projects or NotebookLM.

                                                                                                                                                                  ## Output formats
                                                                                                                                                                  Results are an Apify dataset, so you can download them as JSON, JSONL, CSV, Excel, XML or HTML. This Actor does **not** create SRT or VTT subtitle files; build them from `segments` (start, end, text) if you need them.

                                                                                                                                                                  ## Pricing
                                                                                                                                                                  Pay per event: **$0.003 per transcript ($3 per 1,000)** plus Apify's standard $0.005 run-start fee. You only pay for transcripts you actually get. Set a maximum cost per run in Apify and the scraper stops cleanly when it's reached.

                                                                                                                                                                  ## Use cases
                                                                                                                                                                  - Feed **YouTube transcripts to ChatGPT, Claude or your RAG / vector database**
                                                                                                                                                                  - Turn videos into blog posts, newsletters, show notes and chapters
                                                                                                                                                                  - **YouTube subtitles download** for translation and accessibility work
                                                                                                                                                                  - Keyword, sentiment and competitor research across whole channels
                                                                                                                                                                  - Build datasets of podcast and lecture transcripts

                                                                                                                                                                  ## FAQ
                                                                                                                                                                  **Do I need a YouTube API key or account?** No.

                                                                                                                                                                  **Does it work for videos with only auto-generated captions?** Yes. Most videos only have auto captions, and they're used automatically unless you turn **Use auto-generated captions** off.

                                                                                                                                                                  **Can it download subtitles in another language?** Yes, any language the video has subtitles or captions in. Put the codes in **Preferred languages**. `availableLanguages` lists every language each video offers.

                                                                                                                                                                  **What if a video has no captions at all?** You get `status: "no_transcript"` and aren't charged. This tool doesn't do speech-to-text.

                                                                                                                                                                  **Do I need proxies?** Usually not. If YouTube throttles, the scraper switches to Apify Proxy by itself. For very large jobs you can choose residential proxies.

                                                                                                                                                                  **Is it legal?** It only reads publicly available captions. Respect YouTube's terms, copyright and privacy laws such as GDPR when you use the data.

                                                                                                                                                                  Related: [Website to Markdown for AI, LLM & RAG](https://apify.com/ryumoon-data/website-to-markdown-rag) to turn web pages into clean text for the same AI pipelines.



# Actor input Schema

## `videoUrls` (type: `array`):

YouTube video links or 11-character video IDs. Works with watch, youtu.be, Shorts, live and embed links. Bad or private links are skipped with a clear status and never fail the run.
## `channelOrPlaylistUrls` (type: `array`):

Get transcripts for the newest videos of a channel (e.g. https://www.youtube.com/@mkbhd, add /shorts or /streams for those tabs) or every video in a playlist. Use the limit below to control how many.
## `maxVideosPerChannel` (type: `integer`):

How many videos to take from each channel or playlist (newest first for channels).
## `maxVideosTotal` (type: `integer`):

Hard cap on videos processed in this run. 0 = no cap.
## `languages` (type: `array`):

Caption language codes in order of preference, e.g. ["en", "en-GB", "es"]. 'en' also matches en-US, en-GB etc. Leave empty to get the video's original language.
## `allowAutoGenerated` (type: `boolean`):

Fall back to YouTube's automatic (speech-recognition) captions when no human-made subtitles exist. Most videos only have these.
## `preferManualCaptions` (type: `boolean`):

When both exist in a language, pick the uploaded (manual) subtitles over auto-generated ones.
## `fallbackToAnyLanguage` (type: `boolean`):

If none of your preferred languages exist, return the video's original-language transcript instead of skipping it. Turn off to only get your languages.
## `includeSegments` (type: `boolean`):

Add a 'segments' array with start, end, duration (seconds) and text for every caption line.
## `includeTimestampedText` (type: `boolean`):

Add a 'timestampedTranscript' string with one '[m:ss] text' line per caption, handy for show notes and chapters.
## `maxConcurrency` (type: `integer`):

How many videos to fetch at once.
## `proxyConfiguration` (type: `object`):

Not needed for most runs. If YouTube blocks the request, the scraper switches to Apify residential proxies automatically, rotating IPs until one works (included in the price).

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "maxVideosPerChannel": 10,
  "maxVideosTotal": 0,
  "languages": [
    "en"
  ],
  "allowAutoGenerated": true,
  "preferManualCaptions": true,
  "fallbackToAnyLanguage": true,
  "includeSegments": true,
  "includeTimestampedText": true,
  "maxConcurrency": 6,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
````

# Actor output Schema

## `results` (type: `string`):

All transcripts in the run's default dataset.

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

Counts of transcripts saved, videos without captions and skipped inputs.

# 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 = {
    "videoUrls": [
        "https://www.youtube.com/watch?v=aircAruvnKk"
    ],
    "maxVideosPerChannel": 10,
    "languages": [
        "en"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryumoon-data/youtube-transcript-scraper").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 = {
    "videoUrls": ["https://www.youtube.com/watch?v=aircAruvnKk"],
    "maxVideosPerChannel": 10,
    "languages": ["en"],
}

# Run the Actor and wait for it to finish
run = client.actor("ryumoon-data/youtube-transcript-scraper").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 '{
  "videoUrls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "maxVideosPerChannel": 10,
  "languages": [
    "en"
  ]
}' |
apify call ryumoon-data/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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

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/FJ9wMopA4yWMC0sgX/builds/bFccebazDFIREP89b/openapi.json
