# YouTube Transcript Scraper — with speech-to-text fallback (`dangul/youtube-transcript-scraper`) Actor

Extract transcripts from YouTube videos, playlists, and channels. Falls back to speech recognition when a video has no captions.

- **URL**: https://apify.com/dangul/youtube-transcript-scraper.md
- **Developed by:** [Daniel Gulla](https://apify.com/dangul) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$8.00 / 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.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

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

Extract transcripts from YouTube videos, playlists, and entire channels — as clean full text,
timestamped segments, and ready-to-use SRT subtitles.

**The difference: this actor also handles videos that have no captions.** Most transcript
scrapers return an error the moment a video has no subtitle track. This one transcribes the
audio with speech recognition instead, so you get a usable transcript either way.

### Quick start

Paste a video URL and run it. That is the whole setup.

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

Or point it at a whole channel or playlist:

```json
{
  "channelUrl": "https://www.youtube.com/@mkbhd",
  "maxVideos": 25,
  "languages": ["en"],
  "includeSrt": true
}
```

### What you get back

| Field | Description |
|---|---|
| `transcript` | The full transcript as clean, continuous text |
| `segments` | Timestamped segments — `start`, `end`, `duration`, `text` |
| `srt` | Ready-to-use SRT subtitle content (optional) |
| `language` | Language code of the transcript |
| `transcriptSource` | `youtube-captions`, `youtube-auto-captions`, or `speech-recognition` |
| `wordCount` | Number of words in the transcript |
| `title` · `channel` · `channelId` | Video and channel metadata |
| `durationSeconds` · `viewCount` | Video statistics |
| `availableLanguages` | Every caption language the video offers |
| `scrapedAt` | ISO timestamp of extraction |

The `transcriptSource` field always tells you where the text came from, so you know whether
you are reading human-written captions, YouTube's auto-captions, or speech recognition.

#### Example output

```json
{
  "videoId": "dQw4w9WgXcQ",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video)",
  "channel": "Rick Astley",
  "durationSeconds": 213,
  "language": "en",
  "transcriptSource": "youtube-captions",
  "wordCount": 486,
  "transcript": "♪ We're no strangers to love ♪ ♪ You know the rules and so do I ♪ ...",
  "segments": [
    { "start": 18.64, "duration": 3.28, "end": 21.92, "text": "♪ We're no strangers to love ♪" }
  ],
  "availableLanguages": ["en", "de-DE", "ja", "pt-BR", "es-419"],
  "scrapedAt": "2026-07-31T09:47:39.257Z"
}
```

### Input options

| Option | Default | What it does |
|---|---|---|
| `videoUrls` | `[]` | Video URLs or IDs. Accepts watch links, `youtu.be`, Shorts, embeds, or bare 11-character IDs |
| `playlistUrl` | — | Transcribes every video in a playlist |
| `channelUrl` | — | Transcribes a channel's most recent uploads. Works with `@handle`, `/channel/`, `/c/`, and `/user/` URLs |
| `maxVideos` | `50` | Hard cap on videos per run |
| `languages` | `["en"]` | Language codes in order of preference. First available match wins |
| `preferManualCaptions` | `true` | Prefer human-written captions over auto-generated ones — they are noticeably more accurate |
| `asrFallback` | `true` | Transcribe the audio when no captions exist at all |
| `includeSegments` | `true` | Return timestamped segments alongside the full text |
| `includeSrt` | `false` | Also return an SRT subtitle string |

You can combine `videoUrls`, `playlistUrl`, and `channelUrl` in a single run. Duplicates are
removed automatically.

### What people use it for

- **Content repurposing** — turn long videos into blog posts, newsletters, and social clips
- **AI and RAG pipelines** — feed video content into embeddings, summarisation, or Q\&A
- **Research at scale** — search across hundreds of videos by what was actually said
- **Subtitling and localisation** — export SRT, then translate
- **SEO** — publish transcripts so video content becomes indexable text
- **Accessibility** — provide text alternatives for video content
- **Competitive and market research** — track how topics are discussed across channels

### Pricing

Pay per transcript. **You are charged only for transcripts actually delivered** — videos that
are private, deleted, region-blocked, or otherwise fail cost you nothing. Failed videos still
appear in the dataset with an `error` field explaining why, so nothing disappears silently.

### Reliability notes

- Videos are processed independently. One failure never aborts the run.
- Requests are retried automatically on transient network and rate-limit errors.
- Private, deleted, and age-restricted videos cannot be transcribed.
- Live streams can only be transcribed once they have finished processing.
- Speech recognition is used only when a video has no captions in any requested language. It
  is accurate for clear speech and less so over heavy background music or overlapping speakers.
- Very long videos are truncated when falling back to speech recognition.

### Legal

This actor reads publicly available data only. It does not access private videos, bypass
age restrictions, or require you to provide YouTube credentials. You are responsible for
ensuring your use of the extracted data complies with YouTube's Terms of Service and with
copyright law in your jurisdiction.

### Support

Missing a field, need another output format, or hit a video that should work but does not?
Open an issue on the **Issues** tab of this actor. Reports that come with the video URL are
usually fixed quickly.

# Actor input Schema

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

YouTube videos to transcribe. Accepts full URLs, youtu.be links, Shorts links, or bare 11-character video IDs.

## `playlistUrl` (type: `string`):

Optional. Transcribe every video in a playlist, up to the limit below.

## `channelUrl` (type: `string`):

Optional. Transcribe the channel's most recent uploads, up to the limit below.

## `maxVideos` (type: `integer`):

Hard cap on how many videos this run will process.

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

Language codes in order of preference, e.g. en, es, id. The first available match wins.

## `preferManualCaptions` (type: `boolean`):

Use human-written captions when they exist; fall back to YouTube's auto-captions otherwise. Human captions are far more accurate.

## `asrFallback` (type: `boolean`):

If a video has no captions at all, transcribe its audio with speech recognition instead of returning nothing. This is what most other transcript scrapers cannot do.

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

Return the transcript broken into timestamped segments in addition to the full text.

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

Also return a ready-to-use .srt subtitle string.

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

Optional proxy settings. Usually not needed.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxVideos": 50,
  "languages": [
    "en"
  ],
  "preferManualCaptions": true,
  "asrFallback": true,
  "includeSegments": true,
  "includeSrt": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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=dQw4w9WgXcQ"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dangul/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=dQw4w9WgXcQ"] }

# Run the Actor and wait for it to finish
run = client.actor("dangul/youtube-transcript-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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=dQw4w9WgXcQ"
  ]
}' |
apify call dangul/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=dangul/youtube-transcript-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/kKYektUztTmQf77WI/builds/X6YIj5Q66NWigPlQ5/openapi.json
