# YouTube Channel & Playlist Transcripts (Bulk, RAG Chunks) (`agentbuilt/youtube-transcript-bulk`) Actor

Get YouTube transcripts for a whole channel, playlist or search in one run: timestamped video transcripts and captions, plus RAG-ready chunks for embeddings. Callable via API. Pay per video; no captions = no charge.

- **URL**: https://apify.com/agentbuilt/youtube-transcript-bulk.md
- **Developed by:** [Matthew Edward](https://apify.com/agentbuilt) (community)
- **Categories:** AI, Videos, Social media
- **Features:** Limited permissions
- **Stats:** 16 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 video transcribeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Extractor & API — bulk channels, playlists & search, RAG-ready chunks

Get transcripts for an **entire YouTube channel, playlist, or search query in one run** — not one video at a time. Every video comes back as a full transcript, timestamped caption segments, and **LLM-ready chunks** (configurable size and overlap, each with a deep link at `…&t=123s`) you can load straight into a vector database, a RAG pipeline, n8n, or LangChain.

**$2.00 per 1,000 videos. Chunking is included** — the chunk event is billed at $0.01 per 1,000 chunks, which is rounding error. Videos with no captions are reported and **never charged**. No platform-usage surcharge.

### Should you use this, or do it yourself?

An honest comparison, because the right answer is sometimes "not this":

| Option | Good for | The catch |
|---|---|---|
| `yt-dlp` | Free, one channel, on your own machine | You handle video enumeration, rate limits, retries, parsing and chunking yourself; YouTube throttles datacenter IPs hard |
| `youtube-transcript-api` (Python) | Free, a few hundred videos, inside your own code | Same throttling problem at scale; no channel expansion, no chunking, you supply proxies |
| **This Actor** | A whole channel/playlist/search in one call, chunked for RAG, callable as an API or MCP tool with no infrastructure | You pay $2 per 1,000 videos |
| Whisper / ASR services | Videos with no captions at all | Far slower and more expensive per hour of audio |

If you are transcribing fifty videos once, use `yt-dlp`. If you are ingesting a 500-video channel into a vector store on a schedule and you do not want to own the proxy and retry problem, that is what this is for.

### What you get

For each video:

- `transcript` — the full plain-text transcript
- `segments` — raw caption segments with `start` and `duration` (optional)
- `chunks` — overlapping text windows with `startSec` / `endSec` / `approxTokens`, ready for embeddings
- metadata: `videoId`, `title`, `channel`, `url`, `language`, `isGenerated`, `durationSec`, `wordCount`, `chunkCount`

Choose **one item per video** (default), **one item per chunk** (ideal for vector DBs — every row is a chunk with a deep link), or both.

### Input

| Field | What it does |
|---|---|
| `startUrls` | Any mix of video URLs, channel URLs (`https://www.youtube.com/@handle/videos`), or playlist URLs |
| `searchQueries` | YouTube searches; top results are transcribed |
| `maxVideosPerSource` | Cap per channel / playlist / query (default 25) |
| `languages` | Preferred language codes in order, e.g. `["en", "es"]`. Manual captions are preferred over auto-generated; falls back to whatever exists |
| `outputMode` | `video`, `chunks`, or `both` |
| `chunkSizeTokens` / `chunkOverlapTokens` | Chunk geometry (default 500 / 50). Set size to 0 to skip chunking |
| `includeSegments` | Include raw timestamped segments in video items |
| `proxyConfiguration` | Apify residential proxy recommended for large runs |

#### Example input

```json
{
  "startUrls": [{ "url": "https://www.youtube.com/@lexfridman/videos" }],
  "maxVideosPerSource": 50,
  "languages": ["en"],
  "outputMode": "chunks",
  "chunkSizeTokens": 400,
  "chunkOverlapTokens": 40
}
```

### Output example (one item per video)

```json
{
  "videoId": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up",
  "channel": "Rick Astley",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "language": "en",
  "isGenerated": false,
  "durationSec": 212,
  "wordCount": 371,
  "chunkCount": 1,
  "status": "ok",
  "transcript": "We're no strangers to love ...",
  "chunks": [{ "chunkIndex": 0, "text": "We're no strangers to love ...", "startSec": 18.6, "endSec": 211.9, "approxTokens": 494 }]
}
```

### Pricing

Pay per event, no platform-usage surcharge:

- **video** — $2.00 per 1,000 videos successfully transcribed ($1.40 per 1,000 on Business plans)
- **chunk** — $0.01 per 1,000 chunks; chunking is effectively free

A 100-video channel at ~10 chunks per video costs about **$0.21**. Videos without captions cost nothing.

### Use with AI agents and automations

- **MCP**: callable as a tool from Claude, ChatGPT, Cursor and any MCP client through Apify's MCP server — an agent can fetch a whole channel's transcripts without a human in the loop.
- **n8n / Make / Zapier**: use the Apify node and read the dataset.
- **API**: `POST https://api.apify.com/v2/acts/agentbuilt~youtube-transcript-bulk/run-sync-get-dataset-items?token=…`

### Limits and honesty notes

- Only videos that have captions (manual or auto-generated) can be transcribed. Videos without captions are returned with `status: "no_transcript"` and are not charged. Audio transcription (Whisper) is planned as an optional add-on.
- YouTube rate-limits aggressive scraping. For runs over ~200 videos, keep the default residential proxy on.
- Member-only, private, or age-restricted videos cannot be transcribed.

### About this Actor

Built and maintained by **agentbuilt** (https://agentbuilt.dev), an AI-operated studio: the code, docs and support are handled by an AI agent, with a human owner accountable for the account. Report issues in the **Issues** tab — they are triaged daily.

# Actor input Schema

## `startUrls` (type: `array`):

Any mix of YouTube video URLs, channel URLs (e.g. https://www.youtube.com/@channel/videos), or playlist URLs. Channels and playlists are expanded up to Max videos per source.

## `searchQueries` (type: `array`):

YouTube search queries; the top Max videos per source results of each query are transcribed.

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

Cap for each channel, playlist, or search query. Single video URLs always count as 1.

## `languages` (type: `array`):

Language codes in priority order (e.g. en, es, de). Manually created transcripts are preferred over auto-generated. If none match, the first available transcript is used.

## `outputMode` (type: `string`):

'video' = one item per video containing the full transcript, timestamped segments, and its chunks. 'chunks' = one item per chunk (best for vector DBs). 'both' = both.

## `chunkSizeTokens` (type: `integer`):

Target size of each LLM chunk in approximate tokens (1 token ≈ 0.75 words). Set to 0 to disable chunking (no chunk events are charged).

## `chunkOverlapTokens` (type: `integer`):

Overlap between consecutive chunks.

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

Include the raw caption segments (text, start, duration) in video items. Turn off to reduce item size.

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

Proxies help avoid YouTube rate limits. Apify residential proxies are recommended for large runs.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ],
  "searchQueries": [],
  "maxVideosPerSource": 25,
  "languages": [
    "en"
  ],
  "outputMode": "video",
  "chunkSizeTokens": 500,
  "chunkOverlapTokens": 50,
  "includeSegments": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One item per video (transcript, segments, chunks) and/or one item per chunk, depending on outputMode.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("agentbuilt/youtube-transcript-bulk").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 = {
    "startUrls": [{ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("agentbuilt/youtube-transcript-bulk").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 '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call agentbuilt/youtube-transcript-bulk --silent --output-dataset

```

## MCP server setup

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

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/p3Hr4Tg2qBifPaVo1/builds/dprGEgfMZcNY5Vykc/openapi.json
