# YouTube Transcript Scraper (`muhammad4hmed/youtube-transcript-ai`) Actor

Extract YouTube transcripts from videos, playlists, channels or search queries. Works when other transcript scrapers return nothing. Five output formats, 100+ languages, YouTube translation.

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

## Pricing

Pay per event

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?

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 **any YouTube video, playlist, channel, or search query** — in bulk, in five formats, across 100+ languages.

Built for people who need transcripts *reliably*: RAG pipelines, content research, competitor monitoring, subtitle workflows, and LLM training data.

### What makes it different

- **It works when others return nothing.** YouTube gates the public web player: caption URLs scraped from the watch page now return HTTP 200 with an empty body. This Actor drives YouTube's mobile app API instead and falls back across three clients, so it keeps returning transcripts where watch-page scrapers quietly fail.
- **Bulk input, not one video at a time.** Paste a channel URL, a playlist, an `@handle`, or `search:your query` and it expands to every video, with paging.
- **Translation built in.** Pull a transcript in one language and have YouTube translate it to another in the same run.
- **Five output formats.** Plain text, timed JSON segments, SRT, WebVTT, or timestamped Markdown (ideal for chunking into a vector store).
- **You are never charged for a video that fails.** Charging happens only after a transcript is actually in hand.

### Input

| Field | Type | Description |
|---|---|---|
| `urls` | array | Video URLs/IDs, playlist URLs, channel URLs or `@handles`, and `search:<query>` terms |
| `languages` | array | Preferred caption languages, best first (default `["en"]`) |
| `fallbackToAnyLanguage` | boolean | Use any available track when no preferred language matches (default `true`) |
| `preferManualCaptions` | boolean | Prefer human-written captions over auto-generated (default `true`) |
| `translateTo` | string | Translate captions to this language code via YouTube's translator |
| `outputFormat` | string | `text`, `segments`, `srt`, `vtt`, or `markdown` |
| `maxVideos` | integer | Hard cap on videos processed — protects you from an accidental whole-channel run |
| `aiEnrichments` | array | Optional AI summary/key points/chapters — see AI enrichment below |
| `concurrency` | integer | Parallel video fetches (default `5`) |
| `proxyConfiguration` | object | Recommended for large runs — YouTube rate-limits datacenter IPs |

#### Example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=aircAruvnKk",
    "https://www.youtube.com/@3blue1brown",
    "search:retrieval augmented generation"
  ],
  "languages": ["en"],
  "outputFormat": "markdown",
  "maxVideos": 50
}
```

### Output

One dataset item per video:

```json
{
  "videoId": "aircAruvnKk",
  "title": "But what is a neural network? | Deep learning chapter 1",
  "author": "3Blue1Brown",
  "channelId": "UCYO_jab_esuFRV4b17AJtAw",
  "url": "https://www.youtube.com/watch?v=aircAruvnKk",
  "lengthSeconds": 1120,
  "viewCount": 23914996,
  "thumbnail": "https://i.ytimg.com/vi/aircAruvnKk/sddefault.jpg",
  "language": "en",
  "isAutoGenerated": false,
  "availableLanguages": ["ar", "en", "es", "..."],
  "segmentCount": 286,
  "characterCount": 18145,
  "transcript": "This is a 3. It's sloppily written and rendered at an extremely low resolution...",
  "scrapedAt": "2026-08-16T16:52:20.630Z"
}
```

Videos that cannot be processed produce an item with `videoId`, `url`, and `error` — so a failed video is visible in your results instead of silently missing.

### Notes and limits

- **Videos with captions disabled cannot be transcribed.** There is no caption track to fetch. The Actor reports this per video rather than failing the run.
- **Private, deleted, and age-restricted videos** are reported as errors with YouTube's reason.
- **Residential proxy is required, and it is the default.** YouTube blocks datacenter IP ranges outright with *"Sign in to confirm you're not a bot"* — measured on Apify's own servers, 4 of 5 videos failed without one and 4 of 4 succeeded with one. Leave `proxyConfiguration` on its residential default unless you are running from an IP you know YouTube trusts.

### AI enrichment (optional, off by default)

The Actor can also generate a summary, key points and timestamped chapters from each transcript.
This requires the Actor operator to configure an LLM credential; **if none is set, runs return
transcripts only** and log a warning — they never fail, and you are never charged for an
enrichment that did not happen.

Leave `aiEnrichments` empty unless the listing states AI is enabled.

### Configuration (Actor operator)

AI enrichment reaches a model one of two ways. Whichever credential is present wins, preferring
OpenRouter because it needs no provider account.

| Variable | Purpose |
|---|---|
| `APIFY_TOKEN` | **Default route.** Goes through Apify's OpenRouter Actor — no second account, tokens billed as Apify platform usage. Set automatically in every run, but needs a **paid** Apify plan (Free returns HTTP 429). |
| `OPENROUTER_API_KEY` | Optional override — calls openrouter.ai directly, billed to an OpenRouter balance. Takes precedence if set. |
| `ANTHROPIC_API_KEY` | Optional override — calls the Anthropic API with your own key. |
| `LLM_PROVIDER` | Force `openrouter` or `anthropic` instead of auto-detecting. |
| `LLM_MODEL` | Model id. Defaults to `deepseek/deepseek-v4-flash` (OpenRouter) or `claude-haiku-4-5` (Anthropic). |
| `LLM_TIMEOUT_MS` | Request timeout, default `180000`. |

Credential precedence is `OPENROUTER_API_KEY` → `APIFY_TOKEN` → `ANTHROPIC_API_KEY`. With none
of them available the Actor logs a warning and returns transcripts only — it never fails a run.
See [PRICING.md](PRICING.md) for model costs and the per-character charging model.

### Local development

```bash
npm install
npm run build
node dist/main.js     # reads storage/key_value_stores/default/INPUT.json
```

# Actor input Schema

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

Accepts video URLs or IDs, playlist URLs, channel URLs and @handles, and search terms written as `search:your query`.

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

Language codes in priority order. The first available match wins.

## `fallbackToAnyLanguage` (type: `boolean`):

If none of the preferred languages exist, use whatever caption track the video has.

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

Within the same language, prefer manually written captions over auto-generated ones.

## `translateTo` (type: `string`):

Optional language code (e.g. `es`, `de`). Uses YouTube's own caption translation.

## `outputFormat` (type: `string`):

Shape of the `transcript` field in each result.

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

Hard cap on how many videos are processed. Protects you from an accidental whole-channel run.

## `aiEnrichments` (type: `array`):

Optional AI analysis of each transcript. Requires the Actor operator to configure an LLM credential; if none is set the run returns transcripts only and logs a warning — it never fails.

## `aiInstructions` (type: `string`):

Optional extra guidance for the AI, e.g. "focus on pricing and product claims".

## `concurrency` (type: `integer`):

How many videos to fetch in parallel. Lower this if you hit rate limits.

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

Residential proxy is REQUIRED. YouTube blocks datacenter IPs with "Sign in to confirm you're not a bot", so runs without a residential proxy will mostly fail.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=aircAruvnKk",
    "https://www.youtube.com/@3blue1brown",
    "search:retrieval augmented generation"
  ],
  "languages": [
    "en"
  ],
  "fallbackToAnyLanguage": true,
  "preferManualCaptions": true,
  "outputFormat": "text",
  "maxVideos": 100,
  "aiEnrichments": [],
  "concurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped video transcripts and their metadata.

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

// Run the Actor and wait for it to finish
const run = await client.actor("muhammad4hmed/youtube-transcript-ai").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=aircAruvnKk"] }

# Run the Actor and wait for it to finish
run = client.actor("muhammad4hmed/youtube-transcript-ai").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=aircAruvnKk"
  ]
}' |
apify call muhammad4hmed/youtube-transcript-ai --silent --output-dataset

```

## MCP server setup

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

```

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/QyDM3u88MwPlUjVOZ/builds/mbIHd7mezQpPmlz3l/openapi.json
