# YouTube Transcript Scraper (`automation-lab/youtube-transcript`) Actor

Extract timestamped transcripts & subtitles from any public YouTube video. Batch hundreds of URLs, 100+ languages with auto-fallback, no API key required. Returns full video metadata + segments. Export JSON, CSV, Excel.

- **URL**: https://apify.com/automation-lab/youtube-transcript.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Videos, AI, Developer tools
- **Features:** Limited permissions
- **Stats:** 606 total users, 84 monthly users, 100.0% runs succeeded, 4 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.50 / 1,000 transcript extracteds

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

### What does YouTube Transcript Scraper do?

**YouTube Transcript Scraper** extracts **full transcripts, subtitles, and captions** from any public YouTube video — with no YouTube Data API key required. Paste one or more video URLs, a **playlist URL** for an ordered batch, or channel URLs to auto-discover videos; choose your language; and get **timestamped text segments** plus complete video metadata including title, channel, view count, duration, keywords, and thumbnail.

The actor uses YouTube's internal **ANDROID InnerTube API** — the same endpoint the YouTube mobile app uses — which means it works reliably without browser overhead, API quotas, or OAuth credentials. Batch hundreds of videos in a single run.

Try it free: go to [YouTube Transcript Scraper on Apify Store](https://apify.com/automation-lab/youtube-transcript) and click **Try for free**.

### Who is it for?

**Content creators and marketers**

- 📝 Repurpose a YouTube video into a blog post, newsletter, or Twitter thread
- 🔄 Feed transcripts into ChatGPT or Claude to generate summaries, titles, or social copy
- 📌 Extract quotes from interviews for use in articles or email campaigns

**SEO professionals and agencies**

- 🔍 Build text content from video to rank alongside video results on Google
- 🗂️ Analyze transcript keyword density across a YouTube channel
- 📊 Audit a competitor's spoken messaging for topic gaps

**Researchers, academics, and journalists**

- 🎓 Build NLP corpora from lectures, conference talks, and interviews
- 📰 Search and reference spoken content from press conferences without rewatching
- 🌐 Collect multilingual transcripts for cross-language analysis

**Developers and AI/ML engineers**

- 🤖 Feed merged `fullText` into summarization, translation, or Q\&A pipelines
- ⚡ Process hundreds of transcripts overnight via the API with zero manual work
- 🧩 Power RAG (retrieval-augmented generation) systems with timestamped video knowledge

**Educators and e-learning builders**

- 📚 Convert course videos into searchable text notes
- ♿ Generate accessible transcripts for learners who need closed captions
- 🌍 Translate transcripts to other languages via downstream translation APIs

### Why use YouTube Transcript Scraper?

- ✅ **Actually works** — tested on 15+ video types: music, vlogs, tutorials, lectures, news, and Shorts
- 💸 **Best price on Apify Store** — $0.0025/transcript (Bronze), down to $0.00075 for Diamond; up to 75% cheaper than competitors
- 🚀 **Batch processing** — extract hundreds of transcripts in one run (competitors often limit to 1 video per call)
- 🌍 **100+ languages** — auto-generated and manual captions, with smart fallback to the best available language
- 📦 **Full metadata** — title, channel, description, view count, duration, keywords, thumbnail, publish date, available languages
- ⚡ **No browser** — lightweight pure HTTP extraction, no Playwright or Puppeteer overhead
- 🔑 **No API key** — no YouTube Data API quota, no OAuth, no rate limits
- 📅 **Date filtering** — limit channel discovery to videos inside an inclusive publication date range before transcript extraction
- 📄 **Optional PDF export** — set `generatePdf` to create one downloadable PDF transcript per successful video
- 🔗 **Flexible input** — video URLs, short URLs (`youtu.be/`), embed URLs, Shorts URLs, plain 11-character video IDs, channel URLs, and public playlist URLs
- 📋 **Playlist batches in source order** — expand public playlists with `maxVideosPerPlaylist`, preserve playlist order, and deduplicate videos by first occurrence

### What data can you extract?

**🎬 Video metadata (returned for every video):**

| Field | Type | Description |
|-------|------|-------------|
| `videoId` | string | YouTube video ID (11 characters) |
| `videoUrl` | string | Full YouTube URL |
| `videoTitle` | string | Video title |
| `channelName` | string | Channel display name |
| `channelId` | string | Channel ID (UC-prefixed) |
| `description` | string | Full video description |
| `viewCount` | number | Exact view count |
| `durationSeconds` | number | Duration in seconds |
| `keywords` | array | Video tags/keywords set by creator |
| `thumbnail` | string | Highest-resolution thumbnail URL |
| `publishDate` | string | Publication date (ISO 8601) |
| `availableLanguages` | array | All available caption languages |

**📝 Transcript data:**

| Field | Type | Description |
|-------|------|-------------|
| `language` | string | Language code of selected transcript (e.g. `en`) |
| `selectedLanguage` | string | Full language name (e.g. `English`) |
| `isAutoGenerated` | boolean | `true` if captions are auto-generated by YouTube |
| `segments` | array | Timestamped text segments (see below) |
| `segmentCount` | number | Total segments in the transcript |
| `fullText` | string | All segments merged into one string (optional, enable via `mergeSegments`) |

**⏱️ Each segment contains:**

| Field | Type | Description |
|-------|------|-------------|
| `text` | string | Caption text (HTML entities decoded) |
| `start` | number | Start time in seconds |
| `duration` | number | Segment duration in seconds |

### Run memory

Current builds use **512 MiB** as the minimum, default and maximum allocation. Requests for less or more memory are constrained to **512 MiB**: this provides batch-processing headroom while avoiding oversized allocations, without reducing video batch sizes or discovery limits. Allow enough run time for large batches. Older pinned builds and already-running jobs may retain their previous allocation.

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

This Actor uses **pay-per-event** pricing — you pay only for what you extract.
No monthly subscription. All platform costs (compute, proxy, storage) are **included**.

| Apify plan | Run start | Price per transcript |
|---|---:|---:|
| Free | $0.00300 | $0.00300 |
| Bronze | $0.00250 | $0.00250 |
| Silver | $0.00200 | $0.00200 |
| Gold | $0.00150 | $0.00150 |
| Platinum | $0.00100 | $0.00100 |
| Diamond | $0.00075 | $0.00075 |

The run-start event is charged once; the transcript event is charged for each successful extraction.

**Real-world cost examples:**

| Use case | Videos | Cost (Free tier) |
|---|---|---|
| Single video transcript | 1 | ~$0.006 |
| YouTube playlist (20 videos) | 20 | ~$0.063 |
| Channel analysis (100 videos) | 100 | ~$0.303 |
| Research dataset (1,000 videos) | 1,000 | ~$3.003 |

**Compared to competitors:** starvibe charges $0.005/video, karamelo charges $0.005–$0.007/video, pintostudio and topaz_sharingan charge $0.01/video. Our batch processing makes bulk extraction significantly cheaper when you include the $0.003 start fee savings per run.

On the **free $5 credit** that every new Apify account gets, you can extract approximately **1,600 transcripts**.

### How to get YouTube video transcripts

1. Go to [YouTube Transcript Scraper](https://apify.com/automation-lab/youtube-transcript) on Apify Store
2. Click **Try for free** (no credit card needed for the free $5 credit)
3. Paste one or more YouTube video URLs, public playlist URLs, or channel URLs into the **Videos** field
4. For a playlist URL, optionally set `maxVideosPerPlaylist` (default: `50`, range: 1–500)
5. Set your preferred language code (default: `en` for English)
6. Optionally enable **Merge into full text** to get a single string per video
7. Optionally enable **Generate PDF transcript files** to store downloadable PDFs in the run key-value store
8. Click **Start** and wait seconds to minutes depending on batch size
9. Download transcripts as **JSON, CSV, or Excel** from the dataset view, or open `pdfUrl` for generated PDFs

**Example inputs:**

Minimal — single video:

```json
{
    "urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "language": "en"
}
```

Batch with merge:

```json
{
    "urls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "https://youtu.be/jNQXAC9IVRw",
        "9bZkp7q19f0"
    ],
    "language": "en",
    "includeAutoGenerated": true,
    "mergeSegments": true
}
```

Public playlist in playlist order:

```json
{
    "urls": ["https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"],
    "language": "en",
    "maxVideosPerPlaylist": 20,
    "mergeSegments": true
}
```

A watch URL containing both `v` and `list` is treated as the playlist workflow, not as a single-video input. Playlist videos are processed in playlist order and deduplicated with direct videos and channel discoveries by first occurrence.

Channel URLs may point to a channel root or a recognized tab such as `/about`, `/shorts`, or `/playlists`; discovery uses that channel's `/videos` tab. This does not make unavailable channels accessible.

Channel with an inclusive publication-date filter:

```json
{
    "urls": ["https://www.youtube.com/@lexfridman"],
    "language": "en",
    "maxVideosPerChannel": 20,
    "startDate": "2026-03-01"
}
```

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | array | required | YouTube video URLs, video IDs, Shorts URLs, public playlist URLs, or channel URLs |
| `language` | string | `"en"` | Preferred transcript language code (ISO 639-1). Automatic fallback if unavailable |
| `includeAutoGenerated` | boolean | `true` | Include YouTube auto-generated captions when manual captions aren't available |
| `mergeSegments` | boolean | `false` | Add `fullText` field with all segments as a single string |
| `generatePdf` | boolean | `false` | Generate one downloadable PDF transcript per successful video and add PDF metadata fields to the dataset item |
| `maxVideosPerPlaylist` | integer | `50` | Max videos per public playlist URL, preserving playlist order. Range: 1–500 |
| `maxVideosPerChannel` | integer | `50` | Max videos per channel URL (newest first). Range: 1–500 |
| `startDate` | string | — | For channel URLs, only discover videos published on or after this date (inclusive, YYYY-MM-DD) |
| `endDate` | string | — | For channel URLs, only discover videos published on or before this date (inclusive, YYYY-MM-DD) |

### Output examples

**Transcript with segments:**

```json
{
    "videoId": "dQw4w9WgXcQ",
    "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "videoTitle": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
    "channelName": "Rick Astley",
    "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "description": "The official video for \"Never Gonna Give You Up\" by Rick Astley...",
    "viewCount": 1600000000,
    "durationSeconds": 213,
    "keywords": ["rick astley", "never gonna give you up"],
    "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
    "publishDate": "2009-10-25",
    "language": "en",
    "selectedLanguage": "English",
    "isAutoGenerated": false,
    "availableLanguages": ["English", "Spanish", "French", "German (auto-generated)"],
    "segments": [
        { "text": "We're no strangers to love", "start": 18.0, "duration": 3.0 },
        { "text": "You know the rules and so do I", "start": 21.0, "duration": 3.0 }
    ],
    "segmentCount": 61
}
```

**With `mergeSegments: true`, the item also includes:**

```json
{
    "fullText": "We're no strangers to love You know the rules and so do I..."
}
```

**With `generatePdf: true`, successful transcript items also include:**

```json
{
    "pdfKey": "transcript-dQw4w9WgXcQ.pdf",
    "pdfUrl": "https://api.apify.com/v2/key-value-stores/.../records/transcript-dQw4w9WgXcQ.pdf",
    "pdfFileName": "Rick Astley - Never Gonna Give You Up-dQw4w9WgXcQ.pdf",
    "pdfContentType": "application/pdf",
    "pdfSizeBytes": 84231
}
```

PDF files are stored in the run default key-value store. They include the video URL, title, channel, publish date, selected language, manual/auto-generated caption marker, thumbnail when available, and timestamped transcript text.

### Diagnostic privacy

Failed operations send sanitized diagnostic input, exceptions, and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL query strings are removed; reports are retained for 30 days. Expected empty results and recovered retries are not reported as terminal errors.

This Actor does not use generative AI or send data to an AI provider for training. YouTube supplies the public captions and metadata; Apify hosts the run, storage, and the US datacenter and residential proxies. Service and proxy costs are included in the documented charge events. Diagnostic processing is hosted on our private service, separate from result storage.

Datasets, optional PDFs, and run logs remain in your Apify account under your platform retention settings until you delete them; the Actor does not create a separate persistent result cache. Delete the run and its associated storage in Apify to remove results. Do not submit credentials, secret query parameters, or non-public personal data in video URLs. YouTube names are used descriptively; this Actor is not affiliated with or endorsed by YouTube or Google.

### Tips for best results

- 📦 **Batch your requests** — paste a public playlist URL or combine 100 videos in one run to save 99 start fees versus 100 separate runs
- 📋 **Bound playlist runs** — start with a low `maxVideosPerPlaylist`; public playlists keep playlist order, while private or login-required playlists are unsupported
- 🆔 **Use video IDs directly** — plain 11-character IDs like `dQw4w9WgXcQ` work just as well as full URLs
- 🤖 **Keep `includeAutoGenerated: true`** — many videos (especially non-English) only have auto-generated captions
- 🧠 **Use `mergeSegments: true` for LLM pipelines** — the `fullText` field gives the entire transcript as one string, ready for summarization
- 📄 **Use `generatePdf: true` only when you need files** — default runs stay transcript-only and fast
- 📋 **Check `availableLanguages` in the output** — if you need a different language, re-run with the correct code
- 📅 **Use `startDate` for channel monitoring** — set a valid `YYYY-MM-DD` window to discover only in-range channel videos; direct video and playlist inputs are unchanged
- ⚠️ **Videos without captions** — Shorts, music-only videos, and some older uploads have no captions; they return `segmentCount: 0` with full metadata

### How to download YouTube subtitles and captions

YouTube Transcript Scraper retrieves subtitles using YouTube's internal InnerTube API — the same way the YouTube player loads captions. You get the exact text a viewer sees when they enable captions.

**Supported caption types:**

- 📝 **Manual captions** — professionally created or uploaded by the video owner (highest accuracy)
- 🤖 **Auto-generated captions** — created by YouTube's speech recognition (most English videos and many others)
- 🌐 **Community captions** — user-contributed translations where enabled by the creator

**Export formats from the Apify dataset:**

- **JSON** — structured data with timestamps, ideal for programmatic use
- **CSV** — flat format, one row per video, easy to open in Excel or Google Sheets
- **Excel (.xlsx)** — ready-to-open spreadsheet with all metadata and transcript columns

To download: run the Actor → click **Export** in the Dataset view → choose your format.

### How to get transcripts without the YouTube Data API

The official YouTube Data API v3 does **not** expose transcript or caption text to third-party developers — it only lets you list available caption tracks. To read the actual text, you need a different approach.

YouTube Transcript Scraper uses YouTube's **ANDROID InnerTube API** — the same internal endpoint used by the YouTube mobile app to load captions. This approach:

- 🚫 Requires **no YouTube API key** or quota
- 🌍 Works on **any public video** with captions enabled
- ⏱️ Returns **more detailed segmentation** than web-based extraction
- ♾️ Is **not subject** to the YouTube Data API's 10,000 daily unit quota

This makes it ideal for developers who need transcripts at scale without managing API keys, OAuth flows, or quota limits.

### Integrations

Connect YouTube Transcript Scraper with your existing workflows:

- 📊 **YouTube Transcript → Google Sheets** — schedule daily extraction of a channel's new videos and append transcripts to a running spreadsheet for content analysis
- 🤖 **YouTube Transcript → OpenAI/Claude** — pipe `fullText` into a summarization prompt to auto-generate blog posts or show notes from every new episode
- 📧 **YouTube Transcript → Email** — use Make or Zapier to send a formatted transcript digest when a watched channel publishes a new video
- 🔔 **Webhook on completion** — trigger a downstream pipeline (keyword extraction, translation, indexing) as soon as the run finishes
- 📅 **Scheduled channel monitoring** — run weekly with `startDate` set to last week to continuously capture new transcripts from research channels

Learn more about [Apify integrations](https://docs.apify.com/platform/integrations).

### API usage

You can start YouTube Transcript Scraper programmatically using the [Apify API](https://docs.apify.com/api/v2).

**Node.js:**

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('automation-lab/youtube-transcript').call({
    urls: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
    language: 'en',
    mergeSegments: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].fullText);
```

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_API_TOKEN')

run = client.actor('automation-lab/youtube-transcript').call(run_input={
    'urls': ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
    'language': 'en',
    'mergeSegments': True,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items[0]['fullText'])
```

**cURL:**

```bash
curl -X POST "https://api.apify.com/v2/acts/automation-lab~youtube-transcript/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "language": "en",
    "mergeSegments": true
  }'
```

### Use with AI agents via MCP

[YouTube Transcript Scraper](https://apify.com/automation-lab/youtube-transcript) is available as a tool for AI assistants that support the [Model Context Protocol (MCP)](https://docs.apify.com/platform/integrations/mcp).

Add the Apify MCP server to your AI client — this gives you access to all Apify actors, including this one:

#### Setup for Claude Code

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=automation-lab/youtube-transcript"
```

#### Setup for Claude Desktop, Cursor, or VS Code

Add this to your MCP config file:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=automation-lab/youtube-transcript"
        }
    }
}
```

Your AI assistant will use OAuth to authenticate with your Apify account on first use.

#### Example prompts

Once connected, try asking your AI assistant:

- "Use automation-lab/youtube-transcript to get the full transcript of this video and summarize the key points: https://www.youtube.com/watch?v=dQw4w9WgXcQ"
- "Extract the English transcripts for all videos published this month on the @lexfridman channel and merge them into full text"
- "Get the transcript for this YouTube lecture and extract all timestamps where the speaker mentions machine learning"

Learn more in the [Apify MCP documentation](https://docs.apify.com/platform/integrations/mcp).

### Is it legal to scrape YouTube transcripts?

YouTube Transcript Scraper only accesses publicly available captions and metadata from YouTube videos. It does not bypass any login walls, age restrictions, or access controls. The data collected is the same as what any viewer can access by clicking the CC button on a public YouTube video.

Web scraping of publicly available data is generally considered legal — particularly for non-commercial research and content analysis purposes — but you should review [YouTube's Terms of Service](https://www.youtube.com/static?template=terms) and applicable laws in your jurisdiction. Use the data responsibly and in compliance with privacy regulations like GDPR and CCPA. Read more about the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### FAQ

**Can I extract transcripts from private or age-restricted videos?**
No. This Actor only works with public YouTube videos. Private, unlisted, or age-restricted videos that require a login will return an error message with the video ID so you can identify which ones failed.

**What happens if YouTube requests stall?**
Each transcript extraction attempt has a cumulative 45-second deadline covering page, player, engagement, captions, and internal retries. The Actor makes at most two attempts with fresh proxy URLs (datacenter for video pages and caption files, residential for the player request), and tries a fresh residential connection within an attempt if YouTube shows a bot check. Videos YouTube clearly reports as age-restricted or private are not retried. Exhaustion returns an explicit per-video error row without a transcript charge; other videos continue. Large batches still require a suitable overall run timeout.

**What happens if a video doesn't have captions?**
The Actor returns the full video metadata with `segmentCount: 0` and an empty `segments` array. No error is thrown. You still get the title, description, view count, publish date, and other fields.

**Which languages are supported?**
All languages available on YouTube — over 100 languages including auto-generated captions. Set `language` to any ISO 639-1 code: `en`, `es`, `de`, `ja`, `ko`, `ar`, `hi`, `pt`, `fr`, `zh`, etc. If your preferred language isn't available, the Actor automatically falls back to the best available option and records it in `selectedLanguage`.

**How many videos can I process in one run?**
There is no hard limit. The Actor extracts up to three videos at a time and still writes results in input order (playlist and channel order preserved). When `generatePdf` is on, PDFs are rendered one at a time to keep memory bounded, so PDF runs of long transcripts are somewhat slower. With the default 15-minute timeout, a batch of about 200 videos typically completes; for larger batches or date-filtered channel discovery, raise the run timeout. For very large datasets (10,000+ videos), consider splitting into multiple runs scheduled across time.

**What happens if my run times out or is resurrected?**
Results written so far stay in the dataset. If you resurrect the run, or the platform migrates it to another server, it continues where it stopped: videos already in the dataset are skipped (checked against the dataset itself, so this holds even if a progress save failed), and you are not charged again for them or for the run start. No transcript is ever charged twice: a restart charges only transcripts that were delivered but whose charge was never sent or was rejected. If a charge's outcome can't be confirmed (a transcript or the run start), the run ends as failed rather than succeeded and the charge is never sent again; resurrecting the run later checks it against the run's own charge count. Progress is kept in the run's key-value store under `RUN-PROGRESS` (video IDs and counts) and `RUN-CHARGES` (charge counts only). For a batch that doesn't fit the timeout, resurrect the run or raise its timeout. If you set a maximum total charge, the run stops when it is reached.

**What URL formats are supported?**
Video URLs (`youtube.com/watch?v=...`), public playlist URLs (`youtube.com/playlist?list=...`), watch URLs carrying a `list` parameter, short URLs (`youtu.be/...`), embed URLs (`youtube.com/embed/...`), Shorts URLs (`youtube.com/shorts/...`), channel URLs (`youtube.com/@handle`, `youtube.com/channel/UC...`, `youtube.com/c/Name`), bare `@handles`, and plain 11-character video IDs.

**How are playlists processed?**
The Actor expands public playlists in playlist order, processes at most `maxVideosPerPlaylist` videos per playlist, and deduplicates videos across every playlist, channel, and direct URL by first occurrence. Private, unavailable, malformed, or login-required playlists are logged as actionable errors; valid videos from other inputs continue processing.

**Why are there more segments than the competitor's output?**
This Actor uses the ANDROID InnerTube API, which often returns more detailed caption segmentation than web-based extraction. More segments means more precise timestamps for applications that need accurate time references.

**The transcript is in the wrong language. How do I fix it?**
Set `language` to the desired ISO 639-1 code (e.g., `es` for Spanish, `ja` for Japanese). Check `availableLanguages` in the output to see all options for that video. If the target language has only auto-generated captions, make sure `includeAutoGenerated` is `true`.

**I'm getting `segmentCount: 0`. Why?**
Some videos genuinely have no captions — this is common with Shorts, music videos, and older uploads. Check if captions exist on YouTube by opening the video and clicking the CC button. If captions exist on YouTube but the Actor returns 0 segments, verify that `includeAutoGenerated` is `true`, since many videos only have auto-generated captions that are skipped when this option is off.

**How is this different from the YouTube Data API?**
The YouTube Data API v3 does not expose transcript text — it only lists available caption tracks. This Actor bypasses that limitation by using YouTube's internal InnerTube endpoint, which returns the actual caption text with timestamps. No API key or quota required.

### Related YouTube and video scrapers

- [YouTube Scraper](https://apify.com/automation-lab/youtube-scraper) — scrape YouTube videos, channels, playlists, and comments at scale
- [YouTube Shorts Scraper](https://apify.com/automation-lab/youtube-shorts-scraper) — extract Shorts data from any YouTube channel including views, likes, and engagement
- [YouTube Transcript Enhanced](https://apify.com/automation-lab/youtube-transcript-enhanced) — transcripts with SRT/VTT export, paragraph chunking, and keyword search
- [TikTok Scraper](https://apify.com/automation-lab/tiktok-scraper) — scrape TikTok videos, profiles, and hashtags
- [Instagram Scraper](https://apify.com/automation-lab/instagram-scraper) — extract Instagram posts, reels, profiles, and hashtags

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/youtube-transcript/changelog.md

# Actor input Schema

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

Add YouTube video URLs, public playlist URLs, video IDs, or channel URLs. A watch URL containing a <code>list</code> parameter is expanded as a playlist. Supported formats also include short URLs (<code>youtu.be/...</code>), Shorts URLs, bare video IDs (11 characters), channel URLs (<code>youtube.com/@handle</code>), and bare <code>@handles</code>.

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

Set the preferred transcript language as an ISO 639-1 code (e.g. <code>en</code>, <code>es</code>, <code>de</code>, <code>ja</code>, <code>ko</code>, <code>fr</code>, <code>pt</code>). If the language is unavailable, the actor falls back to the best available option. Check <code>selectedLanguage</code> in the output to see which was used.

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

Enable to fall back to YouTube's auto-generated captions when manual captions are not available. Recommended: leave on — many videos only have auto-generated captions.

## `mergeSegments` (type: `boolean`):

Enable to add a <code>fullText</code> field containing all transcript segments merged into a single string. Useful for feeding directly into LLMs, summarizers, or translation APIs.

## `generatePdf` (type: `boolean`):

Enable to create one downloadable PDF transcript per successful video. PDF records are stored in the run default key-value store and the dataset item includes pdfKey, pdfUrl, pdfFileName, pdfContentType, and pdfSizeBytes. This is optional; when disabled, output stays transcript-only.

## `maxVideosPerPlaylist` (type: `integer`):

Set the maximum number of videos to process from each public playlist URL. Videos keep their playlist order and are deduplicated with all other input videos by first occurrence.

## `maxVideosPerChannel` (type: `integer`):

Set the maximum number of videos to process when a channel URL is provided. Videos are fetched newest first. Keep low (10–20) for testing before running the full channel.

## `startDate` (type: `string`):

For channel URLs, only discover videos published on or after this date (inclusive). Format: <code>YYYY-MM-DD</code>. Direct video and playlist inputs are not filtered.

## `endDate` (type: `string`):

For channel URLs, only discover videos published on or before this date (inclusive). Format: <code>YYYY-MM-DD</code>. Combine with <strong>Start date</strong> to extract a specific channel publication window.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "language": "en",
  "includeAutoGenerated": true,
  "mergeSegments": false,
  "generatePdf": false,
  "maxVideosPerPlaylist": 20,
  "maxVideosPerChannel": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing transcripts and video metadata.

## `files` (type: `string`):

Key-value store containing optional generated transcript PDFs.

# 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=dQw4w9WgXcQ"
    ],
    "language": "en",
    "maxVideosPerPlaylist": 20,
    "maxVideosPerChannel": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/youtube-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 = {
    "urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "language": "en",
    "maxVideosPerPlaylist": 20,
    "maxVideosPerChannel": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/youtube-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 '{
  "urls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "language": "en",
  "maxVideosPerPlaylist": 20,
  "maxVideosPerChannel": 10
}' |
apify call automation-lab/youtube-transcript --silent --output-dataset

```

## MCP server setup

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