# YouTube Transcript Scraper: Channels, Playlists & Search (`wulfcare/youtube-transcript-scraper`) Actor

Get YouTube transcripts (captions and subtitles) as plain text, timestamped segments or SRT for videos, Shorts, whole channels, playlists and searches. Pick the language, fall back to auto-generated captions, and get title, channel, publish date, views and duration with each one.

- **URL**: https://apify.com/wulfcare/youtube-transcript-scraper.md
- **Developed by:** [Wulfcare Data](https://apify.com/wulfcare) (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

$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 Scraper

Transcripts of YouTube videos (captions and subtitles) as **plain text, timestamped segments or SRT**. You can ask for:

- **Videos and Shorts**: paste any YouTube link (watch, youtu.be, Shorts, live, embed) or a bare video id.
- **Whole channels**: an `@handle` or channel URL expands into its videos, newest first. It can also take the channel's **Shorts** and **past live streams**.
- **Playlists**: any public playlist, including a channel's full upload list.
- **YouTube searches**: transcripts of the videos YouTube lists for a search term.

Each transcript comes with the video's **title, channel, publish date, duration, views, category, keywords, description and thumbnail**. You also get a list of **every caption language the video has**.

Need just the **video data**, not what's said? The [Free YouTube Scraper](https://apify.com/wulfcare/youtube-scraper) gets views, likes, comment counts, dates, tags and channel stats for videos, Shorts, channels and searches at no charge per video.

Pick the **language**: `en` gets English, and `["es", "en"]` gets Spanish if there is one, else English. Captions made by the creator are used before YouTube's auto-generated ones. When a video has none of your languages, you get its **original language**, or you can skip it for free. A video with no captions, a private or deleted video or a typo **never crashes the run**. It gets a free row saying what's wrong, and the other videos carry on.

### What people use it for

- **Feeding LLMs and RAG pipelines**: clean transcript text of a whole channel or playlist, ready to chunk and embed. Segment timestamps let answers link back to the exact moment.
- **Content repurposing**: turn videos into blog posts, newsletters, show notes and social posts.
- **Research and monitoring**: what competitors, creators or experts say about a topic, across hundreds of videos, searchable as text.
- **Subtitles**: SRT files for video editors, translation workflows and accessibility.
- **Education and note-taking**: full lecture and course transcripts with timestamps.
- **SEO and keyword research**: what the top videos for a search actually talk about.

### How to use it

1. Add **videos, channels or playlists** (any mix), and/or **YouTube searches**.
2. Set **Max videos per channel, playlist or search** (default 20, 0 = all).
3. Set the **transcript language** (default `en`), or leave it empty to get each video's original language.
4. Run it, then download JSON, CSV or Excel, or call the API.

### What you get: one row per video

```json
{
  "input": "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
  "videoId": "UF8uR6Z6KLc",
  "url": "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
  "title": "Steve Jobs' 2005 Stanford Commencement Address",
  "channelName": "Stanford",
  "channelId": "UC-EnprmCZ3OXyAoG7vjVNCA",
  "channelUrl": "https://www.youtube.com/channel/UC-EnprmCZ3OXyAoG7vjVNCA",
  "publishedAt": "2008-03-08T01:17:20Z",
  "durationSeconds": 904,
  "viewCount": 49151066,
  "category": "Education",
  "language": "en",
  "languageName": "English - English",
  "isAutoGenerated": false,
  "wordCount": 2262,
  "text": "This program is brought to you by Stanford University. Please visit us at stanford.edu. Thank you. I am honored to be with you today ...",
  "segments": [
    { "start": 7.05, "duration": 5.981, "text": "This program is brought to you by Stanford University." },
    { "start": 13.031, "duration": 2.001, "text": "Please visit us at stanford.edu" }
  ],
  "srt": null,
  "availableLanguages": [
    { "language": "ar", "name": "Arabic", "isAutoGenerated": false },
    { "language": "en", "name": "English (auto-generated)", "isAutoGenerated": true },
    { "language": "en", "name": "English - English", "isAutoGenerated": false }
  ],
  "isLive": false,
  "keywords": ["steve jobs", "stanford", "commencement"],
  "description": "Drawing from some of the most pivotal points in his life, Steve Jobs ...",
  "thumbnail": "https://i.ytimg.com/vi/UF8uR6Z6KLc/hqdefault.jpg",
  "error": null
}
```

- `text` is the whole transcript as one string. `segments` has the caption lines with `start` and `duration` in seconds. `srt` is optional (off by default).
- `input` is what you entered (the video, channel, playlist or search the video came from), so you can group results.
- Every column is on every row (`null` when there's no value), and the columns don't change between runs.

#### When there's no transcript

A free row with `error` set, and whatever video details YouTube gave:

```json
{ "videoId": "LXb3EKWsInQ", "title": "COSTA RICA IN 4K 60fps HDR (ULTRA HD)", "text": null, "error": "This video has no captions (neither uploaded nor auto-generated)" }
```

Other errors: `Video unavailable: This video is private`, `Age-restricted video: YouTube only shows it to signed-in users`, `No es captions. Available: en, en (auto)` (with *Skip the video*), `Channel not found`, `The playlist does not exist.`, `This channel has no Shorts tab`.

### Pricing

**$3 per 1,000 transcripts** ($0.003 each). You only pay for rows with a transcript. Videos without captions, unavailable videos and bad inputs are free.

### Input examples

**One video**

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

**A channel's last 100 videos and Shorts, plain text only**

```json
{ "urls": ["https://www.youtube.com/@3blue1brown"], "channelTabs": ["videos", "shorts"], "maxVideosPerSource": 100, "includeSegments": false }
```

**Every video in a playlist, with SRT subtitles**

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

**Spanish transcripts of the top 50 videos for a search, skipping videos without Spanish**

```json
{ "searchQueries": ["receta paella"], "maxVideosPerSource": 50, "languages": ["es"], "ifLanguageMissing": "skip" }
```

### Good to know

- **Languages come from YouTube.** You get captions the creator uploaded, or YouTube's auto-generated ones. Auto-generated captions are only in the language spoken in the video. This Actor doesn't machine-translate; `availableLanguages` shows what each video has.
- **Auto-generated captions** have no punctuation on some videos and may mishear names. Turn off *Use auto-generated captions* to accept only captions made by a person.
- **Speed**: each IP address YouTube trusts gives about **40 transcripts a minute** (about 70 with *Publish date and category* off). YouTube refuses an IP for about half an hour if it asks faster, so the Actor paces every IP and spreads the work over all the IPs YouTube accepts. A bigger proxy pool makes big jobs faster. If every IP needs a break, the run waits for one to recover and carries on (the run's status says so).
- **YouTube distrusts many datacenter IP addresses** and asks them to "sign in to confirm you're not a bot". The Actor finds IPs YouTube accepts and keeps using them. If every IP is refused from the start, the run stops with a clear message, and you pay nothing for the failed videos. Run again later, or choose residential proxy.
- **Live streams** have captions once the stream has ended. **Premieres and upcoming streams** have none yet.
- **Age-restricted and members-only videos** need a signed-in account, so they come back as free error rows. Everything else comes from public YouTube, as a logged-out visitor sees it. No Google account is used.

### Other Actors by Wulfcare Data

- [Google Hotels Prices Scraper](https://apify.com/wulfcare/google-hotels-scraper): every booking site's price for any hotel and dates, and hotel searches
- [Free YouTube Scraper](https://apify.com/wulfcare/youtube-scraper): YouTube videos, Shorts, channels and searches with views, likes, comments and channel stats, free
- [App Store Scraper](https://apify.com/wulfcare/app-store-scraper): Apple App Store reviews (no 500 cap), app details, search and charts
- [Google Play Scraper](https://apify.com/wulfcare/google-play-scraper): Google Play reviews, app details, data safety and charts
- [Google Trends Scraper](https://apify.com/wulfcare/google-trends-scraper): interest over time, rising queries and Trending Now
- [Google Jobs Scraper](https://apify.com/wulfcare/google-jobs-scraper): job listings from Google Jobs

Found a problem or need a field? Open an issue on the Issues tab.

# Actor input Schema

## `urls` (type: `array`):

Any mix of video URLs (watch, youtu.be, Shorts, live, embed), 11-character video ids, channel URLs (@handle, /channel/UC..., /c/..., /user/...) and playlist URLs. Channels and playlists are expanded into their videos, newest first, up to the limit below.

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

Optional. Transcripts of the videos YouTube lists for each search term (videos only, YouTube's relevance order).

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

0 = all of them. Single video URLs are always fetched.

## `channelTabs` (type: `array`):

Which of a channel's tabs to take videos from. Each tab counts as its own source for the limit above.

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

Language codes in order of preference (en, es, pt-BR, ja...). "en" also matches en-US and en-GB. Captions uploaded by the creator are used before auto-generated ones in the same language. Leave empty to always get the video's original (spoken) language.

## `ifLanguageMissing` (type: `string`):

Every row says which language it's in (language, isAutoGenerated) and lists all the video's caption languages (availableLanguages).

## `includeAutoGenerated` (type: `boolean`):

Most videos only have YouTube's automatic (speech recognition) captions. Turn off to accept only captions made by a person.

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

segments: \[{start, duration, text}] in seconds, as shown on screen. The full transcript is always in text.

## `includeSrt` (type: `boolean`):

Adds the transcript as an .srt subtitle file (srt field), ready for video editors and players.

## `includePublishDate` (type: `boolean`):

publishedAt and category, from one extra request per video. Off makes big runs about twice as fast: YouTube limits how many videos one IP address may ask for per minute.

## `includeDescription` (type: `boolean`):

The full description text. Title, channel, duration, views, keywords and thumbnail are always included.

## `maxConcurrency` (type: `integer`):

Videos processed at once. YouTube lets each IP address fetch roughly 40-75 videos a minute, so a bigger proxy pool speeds up big runs more than this does.

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

YouTube refuses transcripts to IP addresses it distrusts, which includes many datacenter IPs. The run finds IPs YouTube accepts and keeps using them. If a run reports that every IP was refused, choose residential proxy.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
    "https://www.youtube.com/@3blue1brown"
  ],
  "maxVideosPerSource": 20,
  "channelTabs": [
    "videos"
  ],
  "languages": [
    "en"
  ],
  "ifLanguageMissing": "original",
  "includeAutoGenerated": true,
  "includeSegments": true,
  "includeSrt": false,
  "includePublishDate": true,
  "includeDescription": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "urls": [
        "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
        "https://www.youtube.com/@3blue1brown"
    ],
    "maxVideosPerSource": 20,
    "languages": [
        "en"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("wulfcare/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 = {
    "urls": [
        "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
        "https://www.youtube.com/@3blue1brown",
    ],
    "maxVideosPerSource": 20,
    "languages": ["en"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("wulfcare/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 '{
  "urls": [
    "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
    "https://www.youtube.com/@3blue1brown"
  ],
  "maxVideosPerSource": 20,
  "languages": [
    "en"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call wulfcare/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wulfcare/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/BEcDw67tGEgyosbNu/builds/aAwYw2gP563zLzL6a/openapi.json
