# YouTube Transcript Scraper - Captions, Timestamps, Text (`scrapefy/youtube-transcript-scraper`) Actor

Transcripts of YouTube videos, Shorts, playlists and channels: full text or timestamped segments, auto-generated or manual captions, any language, plus title, channel and views. No login, no API key.

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

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?

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: captions, timestamps and full text from any public video

Get the **transcript of any public YouTube video** without a login, cookies, API key or Google quota. Paste video links (watch, youtu.be, Shorts, embed), video IDs, or a playlist or channel link, and every video comes back as one clean row: video ID and URL, title, channel, publish date, duration, views, **language, whether the captions are auto-generated**, the **full transcript as plain text**, **timestamped segments** (start, duration, text) and the list of all caption languages the video offers. Export to JSON, CSV or Excel, or call it from the API.

Use it to **feed transcripts to AI agents and LLM pipelines (RAG, summaries, Q\&A), repurpose video content, do keyword and topic research, build training sets, monitor a channel, or index lecture and podcast archives**. Works with AI agents through the Apify MCP server. It reads only the **public caption tracks** YouTube shows to every viewer - no video or audio is downloaded.

### Why this one

- **No login, no cookies, no API key.** Public captions only; nothing to configure. A residential proxy is not needed: it runs on Apify's standard proxy pool, and a fresh IP is used on every retry.
- **Videos, Shorts, playlists and channels.** Accepts watch / youtu.be / shorts / embed / live links and bare IDs; playlists and channels are expanded to their newest videos (you set the limit).
- **Language control.** List preferred languages (`en`, `de`, `pt-BR`...); for each, manual captions win over auto-generated ones. If none match, it falls back to the auto-generated track in the spoken language (switchable) and tells you which language and kind you got.
- **Your output shape.** Plain text only, segments only, or both; metadata on or off.
- **Never fails the whole run for one video.** A video with no captions, a private or removed video or a block gets its own row with an `error` message and is **not charged**; the rest continue. A `RUN_SUMMARY` record counts successes and errors.
- **Polite by design.** Small parallelism, pauses between requests, retries with backoff and a new IP, and the run stops politely if YouTube keeps blocking.

### Input (main fields)

| Field | Meaning |
|---|---|
| Video URLs or IDs | One per line: watch, youtu.be, Shorts, embed links or the 11-character ID. Playlist/channel links are expanded too |
| Playlist or channel URLs | Optional; newest videos are listed and transcribed |
| Max videos per playlist/channel | Default 10, max 500 |
| Preferred caption languages | Ordered codes, default `en` |
| Fall back to any available language | Default on |
| Output format | Text and segments (default), text only, or segments only |
| Include video metadata | Title, channel, publish date, duration, views, category, description (first 2,000 characters) |
| Proxy configuration | Apify Proxy on by default (needed: YouTube blocks most datacenter IPs without it) |

### Output (one row per video)

`videoId, url, title, channel, channelId, channelUrl, publishDate, durationSeconds, viewCount, category, isLive, description, language, languageName, isAutoGenerated, segmentCount, wordCount, transcript, segments[{start, duration, text}], availableLanguages[{languageCode, name, isAutoGenerated, isTranslatable}], error, scrapedAt`. A `RUN_SUMMARY` record in the key-value store lists counts (transcripts, no captions, unavailable, blocked), per-video errors and charged events. See `sample-output.json` for real rows (long fields shortened there).

Notes on the data: `viewCount` is the number YouTube shows at scrape time. `publishDate` comes from a second public request that can occasionally be blocked; then it is `null` while the transcript is still returned. Segment times are seconds from the start of the video. Captions are returned as published: auto-generated captions can contain recognition errors, and some tracks are sparse (music videos often carry only lyrics).

### Pricing

Pay per event: **$0.002 per transcript** ($2.00 per 1,000 transcripts) plus a $0.00005 start event per run. Videos without captions, unavailable videos and blocked videos are not charged. A 10-video run costs about two cents. See PRICING.md for the benchmark.

### Public data only

The Actor reads only the public caption tracks and public page data that YouTube offers every viewer. It does **not** log in, use cookies or accounts, read private or members-only videos, download video or audio, or bypass paywalls. Captions and metadata can contain personal data (speaker names, channel names). You are responsible for using the data in line with YouTube's terms of service, copyright law, GDPR and other applicable data-protection law.

### Notes and limits

- Only videos with public captions (manual or auto-generated) return a transcript. Age-restricted, private, members-only, live-in-progress and removed videos usually return an error row.
- Machine translation of captions into other languages is not offered (YouTube blocks that request from cloud IPs); use a language the video already has.
- Playlists and channels return the newest videos first, up to your limit.
- YouTube rate-limits cloud traffic. If you see `blocked` errors, rerun the failed videos later or with a smaller batch.

### FAQ

**How much does it cost?** $0.002 per transcript plus $0.00005 per run. 1,000 transcripts = $2.00. Error rows are free.

**Do I need a YouTube API key or login?** No.

**Does it work for auto-generated captions?** Yes. `isAutoGenerated` tells you which one you got.

**Which languages?** Whatever the video offers; `availableLanguages` lists them. Ask for several in order of preference.

**Can I get a whole channel?** Yes: give the channel link and a `Max videos per playlist/channel` limit (up to 500, newest first).

**Does it download videos or audio?** No. Text only.

**Why did a video return an error?** Common reasons: the video has no captions, is private/removed/age-restricted, or YouTube blocked the request after retries. The `error` field says which.

**Which export formats are available?** JSON, CSV, Excel, XML, HTML or RSS from the Console or API, or Apify integrations such as Make, Zapier, n8n and Google Sheets.

**Something broke or a field is missing?** Open an issue on the Actor's Issues tab with the run link.

### Use with AI agents / MCP

Agents can call this Actor through the [Apify MCP server](https://mcp.apify.com) (`https://mcp.apify.com`). Add the Actor to the server, or let the agent find it with the `search-actors` tool ("youtube transcript"), then call it by name:

- Actor: `santis_hermes/youtube-transcript-scraper`
- Example prompt: "Get the English transcript of https://www.youtube.com/watch?v=dQw4w9WgXcQ as plain text."
- Minimal input:

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

# Actor input Schema

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

YouTube videos to transcribe, one per line. Accepts watch links (youtube.com/watch?v=...), short links (youtu.be/...), Shorts links (youtube.com/shorts/...), embed and live links, or the bare 11-character video ID. Playlist and channel links are also accepted here and expanded using the 'Max videos per playlist/channel' limit.

## `playlistOrChannelUrls` (type: `array`):

Optional playlist links (youtube.com/playlist?list=...) or channel links (youtube.com/@handle, /channel/UC..., /c/name). The newest videos are listed and each one is transcribed. How many is set by 'Max videos per playlist/channel'. Leave empty if you only want the videos above.

## `maxVideosPerList` (type: `integer`):

Maximum number of videos taken from each playlist or channel, newest first (channel Videos tab, playlist order). Keeps the cost of a run predictable. Does not limit the videos you list one by one.

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

Language codes in order of preference, for example en, de, es, pt-BR. For each language the scraper takes manual (human-made) captions first and the auto-generated track second. Matching on the base language also works (en matches en-US).

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

When none of the preferred languages exists, return the first available track (manual first) instead of an error. The language actually returned is in the language and isAutoGenerated fields. Switch off to get an error row instead.

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

Choose what each row contains: the full transcript as one string, the list of segments with start time and duration in seconds, or both. Plain text only gives the smallest rows.

## `includeMetadata` (type: `boolean`):

Adds title, channel name and ID, publish date, duration in seconds, view count as shown on the public page, category and the first 2,000 characters of the description. Switch off for the fastest run with only title and channel.

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

YouTube blocks most datacenter IPs without a proxy, so keep Apify Proxy on (the default pool). Every attempt uses a fresh IP. The proxy cost is included in the per-transcript price.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/arj7oStGLkU"
  ],
  "maxVideosPerList": 10,
  "languages": [
    "en"
  ],
  "fallbackToAnyLanguage": true,
  "outputFormat": "both",
  "includeMetadata": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `transcripts` (type: `string`):

All videos as a table with the key columns.

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

Every video with all fields including segments and available languages.

## `runSummary` (type: `string`):

Counts of transcripts, videos without captions, blocked videos, input errors, charged events.

# 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",
        "https://youtu.be/arj7oStGLkU"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapefy/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",
        "https://youtu.be/arj7oStGLkU",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapefy/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 '{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/arj7oStGLkU"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapefy/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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