# YouTube Transcript Master \[EASY] (WebVTT & more) (`zerohour/yt-transcript`) Actor

YouTube Transcripts in BULK! Easily query via channel, playlist, or video URLs. Built with simplicity & reliability in mind, with expert support. Perfect data to feed your AI or LLM. Output multiple formats: TEXT, JSON, SRV, TTML, VTT (WebVTT). Automatic YouTube captions are available as backup.

- **URL**: https://apify.com/zerohour/yt-transcript.md
- **Developed by:** [Zerohour](https://apify.com/zerohour) (community)
- **Categories:** SEO tools, Videos, AI
- **Stats:** 130 total users, 2 monthly users, 100.0% runs succeeded, 4 bookmarks
- **User rating**: No ratings yet

## Pricing

$37.50/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period. You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 📜 YouTube Transcript Master

This Actor extracts transcripts from YouTube videos a mix of sources like: channel URLs, or playlist URLs, and video URLs. It fetches video metadata (title, duration, upload date) and transcripts in specified formats and languages.

⭐ **Paying users will enjoy recieve quick responses messages, expert support for issues, as well as feature or Actor requests**

<br>

*Why the high price?* <br>

*This a robust Actor built for high volume and bulk dataset for long term use cases. This way I can support the long term users of this Actor more effectively rather than on a "per result" basis. If you would like you may try the lite version of this Actor here: [YouTube Transcript Master \[Lite\]](https://apify.com/zerohour/yt-transcript-lite)*

***

<h2 id="features">🌟 Features</h2>

- Retrieve **transcripts in bulk** with a mix of inputs like: YouTube channels, playlists, or individual video links.
- Extracts video title, duration, and upload date.
- Fetches transcripts in **multiple formats** (Plain Text, JSON, VTT, TTML, etc.).
- Supports specifying the desired transcript **language**.
- Uses **efficient** HTML scraping minimizing CPU usage.
- Includes enhanced retry logic for network requests to improve **reliability**.
- Optionally uses Apify's residential proxies for **consistent results**.

***

<h2 id="usage-costs">📊 Usage & Estimated Costs</h2>

Understanding the potential costs associated with running this Actor is important. Below is an example based on a **test run processing `500` videos** to retrieve **`plainText` transcripts**. Please note that actual costs can vary based on several factors.

**Test Run Statistics:**

- Videos Processed: **500**
- Transcript Format Requested: **`plainText`**
- Total Combined Video Length: **~380 hours**
- Average Video Length: **~45 minutes**
- Success Rate: **100%** (0 missed results or errors)
  <br>

##### Estimated Cost Breakdown (according to test run):

| Cost Category         | Estimated Cost | Notes                                                                 |
| :-------------------- | :------------- | :-------------------------------------------------------------------- |
| Actor Compute Units   | $1.358         | Cost for the server resources used to run the Actor's code.           |
| Proxy (Residential)   | $1.194         | Cost for using Apify's residential proxies to avoid blocks by YouTube. |
| Other (Platform Fees) | $0.004         | Minimal platform usage fees.                                          |
| **Total Estimated Cost** | **$2.56**      |                                                                       |

<br>

**Factors Influencing Costs:**

- **Number of Videos:** The primary driver of cost. More videos mean longer compute time and potentially more proxy usage.
- **Transcript Formats:** Requesting multiple formats per video *might* slightly increase compute time and proxy usage if different underlying fetches are needed.
- **Proxy Usage:** Disabling the proxy (`useApifyProxy: false`) eliminates proxy costs but significantly increases the risk of being blocked by YouTube, leading to failed runs and potentially higher compute costs due to retries or incomplete runs. **Using the proxy is highly recommended.**
  <br>

**Important Considerations:**

- The costs shown are **estimates** based on a specific run and current Apify pricing. Your actual costs may differ.
- While the Actor includes robust error handling and retries, occasional failures for specific videos (due to missing transcripts, YouTube errors, private videos, or persistent proxy issues) can still occur. Check the output dataset's `error` field and Actor logs for details on any failed items.

***

<h2 id="input-schema">⚙️ Input</h2>

The actor takes a JSON object as input with the following properties:

| Field                | Type      | Description                                                                                                                                 | Required | Default                                                                                                 |
| :------------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :------- | :------------------------------------------------------------------------------------------------------ |
| `sources`            | `Array`   | A list of YouTube URLs. Can include video URLs (`watch?v=`), playlist URLs (`playlist?list=`), or channel URLs (`@handle`, `/c/`, `/user/`). | Yes      | `[]`                                                                                                    |
| `formats`            | `Object`  | Specifies which transcript formats to retrieve. Set the desired format key(s) to `true`.                                                      | No       | `{ "plainText": true, "json": false, "json3": false, "srv1": false, "srv2": false, "srv3": false, "ttml": false, "vtt": false }` |
| `language`           | `String`  | The two-letter language code for the desired transcript (e.g., `en`, `es`, `de`).                                                           | No       | `"en"`                                                                                                  |
| `useApifyProxy`      | `Boolean` | If `true`, uses Apify's residential proxies for fetching. Highly recommended to avoid blocks. If `false`, uses the container's direct IP.   | No       | `true`                                                                                                  |
| `delayBetweenVideos` | `Integer` | An optional delay in milliseconds to wait between processing each video. Useful for mitigating rate limits on very large lists.               | No       | `0`                                                                                                     |

#### Input Example

```json
{
    "sources": [
        "https://www.youtube.com/watch?v=b_nep8vMnkc",
        "https://www.youtube.com/@Apify",
        "https://www.youtube.com/playlist?list=PLObrtcm1Kw6PEnu5BpeEFb8XEoQXMw0g7"
    ],
    "formats": {
        "plainText": true, // Get one or many formats
        "json": true,
        "json3": false,
        "srv1": false,
        "srv2": false,
        "srv3": false,
        "ttml": false,
        "vtt":  false
    },
    "language": "en", // Two letter language codes: 'es', 'fr', 'pl', etc.
    "useApifyProxy": true,
    "delayBetweenVideos": 0 // Milliseconds
}
```

***

<h2 id="output-example">📥 Output</h2>

The actor outputs data to the default Apify dataset. Each item in the dataset represents a processed video and has the following structure:

| Field       | Type            | Description                                                                                     |
| :---------- | :-------------- | :---------------------------------------------------------------------------------------------- |
| `url`       | `String`        | The original YouTube video URL processed.                                                       |
| `language`  | `String`        | The language code requested for the transcript.                                                 |
| `title`     | `String`        | The title of the video (`N/A` or 'Processing Error' if extraction failed).                      |
| `duration`  | `Integer`       | The duration of the video in seconds (`0` or `-1` if extraction failed).                        |
| `videoLink` | `String`        | Same as `url`, provided for convenience.                                                        |
| `uploadDate`| `String`|`null` | The publication date of the video (YYYY-MM-DD format), if found.                              |
| `text`      | `String`|`null` | The plain text transcript, if requested and found (with improved handling for `\"`).         |
| `json`      | `Array`|`null`   | Structured JSON transcript (start, duration, text per segment), if requested and found.      |
| `json3`     | `Object`|`null`  | The raw JSON3 format transcript, if requested and found.                                     |
| `srv1`      | `String`|`null` | The raw SRV1 (XML) format transcript, if requested and found.                                |
| `srv2`      | `String`|`null` | The raw SRV2 (XML) format transcript, if requested and found.                                |
| `srv3`      | `String`|`null` | The raw SRV3 (XML) format transcript, if requested and found.                                |
| `ttml`      | `String`|`null` | The raw TTML format transcript, if requested and found.                                      |
| `vtt`       | `String`|`null` | The raw VTT format transcript, if requested and found.                                       |
| `error`     | `String`|`null` | An error message if processing the video or fetching transcripts failed for this video.      |
| `details`   | `String`|`null` | Additional error details (like HTTP status code or stack trace) if an error occurred.        |

#### Output Example (Success - plainText & json requested)

```json
{
  "url": "https://www.youtube.com/watch?v=b_nep8vMnkc",
  "language": "en",
  "title": "Example Video Title",
  "duration": 123,
  "videoLink": "https://www.youtube.com/watch?v=b_nep8vMnkc",
  "uploadDate": "2023-10-27",
  "text": "This is the extracted plain text transcript...",
  "json": [
    { "text": "Segment 1 text", "start": 0.5, "dur": 3.2 },
    { "text": "Segment 2 text", "start": 3.7, "dur": 2.8 }
  ],
  "json3": null,
  "srv1": null,
  "srv2": null,
  "srv3": null,
  "ttml": null,
  "vtt": null,
  "error": null,
  "details": null
}
```

#### Output Example (Failure - general processing error)

```json
{
  "url": "https://www.youtube.com/watch?v=invalidVideoId",
  "language": "en",
  "title": "Processing Error",
  "duration": -1,
  "videoLink": "https://www.youtube.com/watch?v=invalidVideoId",
  "uploadDate": null,
  "text": null,
  "json": null,
  "json3": null,
  "srv1": null,
  "srv2": null,
  "srv3": null,
  "ttml": null,
  "vtt": null,
  "error": "Failed to process: Failed to extract valid playerResponse from HTML after 2 attempts.",
  "details": "Error: Failed to extract valid playerResponse from HTML after 2 attempts.\n    at processVideos (/actor/main.js:497:23)\n    at ..."
}
```

***

<h2 id="usage-notes">📝 Usage Notes</h2>

- **Recent Uploads:** Recently upload videos may not have transcripts right away.
- **Private or Deleted Videos:** Keep in mind these videos will result in errors.
- **Live Streams:** Processing live or upcoming streams may result in errors or incomplete data, as the necessary transcript information might not be available.
- **Large Transcripts & Multiple Formats:** Apify has a 9.4mb limit for each item (transcript), keep this in mind when using multiple formats and large transcripts.

***

<h2 id="support">💬 Support</h2>

If you encounter issues or have questions, contact me @ https://x.com/t\_zerohour.

***

# Actor input Schema

## `sources` (type: `array`):

List of YouTube channels, playlists, and/or video URLs

## `formats` (type: `object`):

Select which transcript formats you want to retrieve, 'true' will return desired format

## `language` (type: `string`):

Two-letter language code (e.g., 'en' for English, 'es' for Spanish)

## `proxyConfiguration` (type: `object`):

Configure the proxies used for making requests.

## `delayBetweenVideos` (type: `integer`):

Delay between processing videos in milliseconds

## Actor input object example

```json
{
  "sources": [
    "https://www.youtube.com/watch?v=b_nep8vMnkc&pp=ygULYXBpZnkgaW50cm8%3D"
  ],
  "formats": {
    "plainText": true,
    "json": false,
    "json3": false,
    "srv1": false,
    "srv2": false,
    "srv3": false,
    "ttml": false,
    "vtt": false
  },
  "language": "en",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "delayBetweenVideos": 0
}
```

# 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 = {
    "sources": [
        "https://www.youtube.com/watch?v=b_nep8vMnkc&pp=ygULYXBpZnkgaW50cm8%3D"
    ],
    "formats": {
        "plainText": true,
        "json": false,
        "json3": false,
        "srv1": false,
        "srv2": false,
        "srv3": false,
        "ttml": false,
        "vtt": false
    },
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zerohour/yt-transcript").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 = {
    "sources": ["https://www.youtube.com/watch?v=b_nep8vMnkc&pp=ygULYXBpZnkgaW50cm8%3D"],
    "formats": {
        "plainText": True,
        "json": False,
        "json3": False,
        "srv1": False,
        "srv2": False,
        "srv3": False,
        "ttml": False,
        "vtt": False,
    },
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("zerohour/yt-transcript").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 '{
  "sources": [
    "https://www.youtube.com/watch?v=b_nep8vMnkc&pp=ygULYXBpZnkgaW50cm8%3D"
  ],
  "formats": {
    "plainText": true,
    "json": false,
    "json3": false,
    "srv1": false,
    "srv2": false,
    "srv3": false,
    "ttml": false,
    "vtt": false
  },
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call zerohour/yt-transcript --silent --output-dataset

```

## MCP server setup

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

```

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/coWWSDwSxmIhTD3La/builds/J1gwyM8rJ9oAn4FDs/openapi.json
