# YouTube Transcript Scraper (`hypebridge/youtube-transcript-scraper`) Actor

Extract YouTube transcripts from videos, playlists, and channel videos. Verify caption language and export subtitle timings with millisecond precision.

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

## Pricing

from $0.24 / 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

## YouTube Transcript Scraper

Extract available YouTube captions as timestamped segments and continuous text. Submit video or Shorts URLs, playlists, channel URLs, and exact 11-character video IDs. Playlists and a channel's Videos tab expand to video IDs before transcript extraction. The scraper uses YouTube's public web interfaces and does not require a Google API key. It returns captions YouTube makes available to the request; it does not transcribe audio when captions are missing.

### What you get

Each processed video produces a record with its canonical watch URL, the original video, playlist, or channel URL in `sourceUrl`, a `sourceType`, market and locale hints, chapter names when exposed by YouTube, segment start times, and optional full text. When `captionLanguage` is explicit, the Actor selects a matching YouTube caption track (preferring manual captions) and retrieves its source timed cues. Those records include `startMilliseconds` and `durationMilliseconds` per segment. With `includeSubtitles: true`, SRT and WebVTT use those exact source timings and report `subtitleTiming: "source_milliseconds"`. Automatic mode keeps the transcript-panel path and reports inferred subtitle end times.

`requestedLocale` records the locale or requested caption language. Use `captionLanguage` to ask for a specific language. The Actor checks YouTube's available caption tracks and prefers a manual track over an auto-generated track in the matched language. If no matching language exists it returns `language_unavailable` instead of silently substituting a different language. Successful explicit requests report the actual `captionLanguage`, `captionTrackName`, and `captionSource` (`manual` or `auto_generated`). Automatic mode retains YouTube's transcript-panel behavior and does not claim a verified language.

### Input

Paste one or more supported YouTube URLs or video IDs in **YouTube video, playlist, or channel URLs**. The input list is capped at 10,000 entries and each value at 2,048 characters. `maxItems` controls the maximum number of unique videos processed across direct URLs and expanded sources. Supported video URL forms include watch, Shorts, live, embed, and `youtu.be`; supported markets include `youtube.com`, `youtube.co.in`, `youtube.com.br`, `youtube.co.jp`, and `youtube.de`. Playlist URLs must use `/playlist?list=…`. Channel URLs can use `@handle`, `/channel/UC…`, `/c/…`, or `/user/…`; these expand the channel's Videos tab. Bare 11-character IDs use the US market by default. Other regional storefront hosts are skipped.

| Field | Default | Description |
|---|---:|---|
| `videoUrls` | `[]` | Video URLs or IDs, playlist URLs, and channel URLs. Each entry may be up to 2,048 characters; duplicate videos are processed once. |
| `maxItems` | `100` | Maximum unique videos to process across all inputs, from 1 to 10,000. |
| `captionLanguage` | `auto` | Optional BCP-47 language code such as `en`, `es`, or `pt-BR`. Selects a matching track, preferring manual captions, and uses YouTube timedtext cues. |
| `preferredLanguage` | `auto` | Legacy compatibility field. It only hints the request locale and does not verify or select a caption track. |
| `proxyCountry` | `AUTO` | Optional market context: `AUTO`, `US`, `IN`, `BR`, `JP`, or `DE`. A URL `gl` market parameter takes precedence. |
| `includeFullText` | `true` | Include transcript text joined into one string. |
| `includeSegments` | `true` | Include individual segments with whole-second start times. |
| `includeSubtitles` | `false` | Include SRT and WebVTT. Explicit `captionLanguage` uses source cue start and duration; automatic mode infers cue end times. |
| `includeChapters` | `true` | Include chapter titles. In exact-language mode, turn off to skip an extra YouTube request; automatic mode already gets chapters with the transcript response. |
| `diagnosticFallback` | `true` | On an empty transcript response, make one bounded watch-page request to classify the result. |
| `maxConcurrency` | `15` | Number of videos processed concurrently, from 1 to 15. Higher concurrency can reduce run time and compute charges. |

Example input:

```json
{
  "videoUrls": [
    "UF8uR6Z6KLc",
    "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj",
    "https://www.youtube.com/@YouTube/videos"
  ],
  "maxItems": 10,
  "captionLanguage": "es",
  "includeSubtitles": true
}
```

Select Spanish captions with source-exact cue timing:

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=UF8uR6Z6KLc"],
  "captionLanguage": "es",
  "includeSubtitles": true
}
```

Process the first 20 videos from a channel's Videos tab:

```json
{
  "videoUrls": ["https://www.youtube.com/@YouTube/videos"],
  "maxItems": 20,
  "includeSegments": false
}
```

### Output and statuses

Results are written to the default dataset. `available` means at least one timestamped transcript segment was extracted. Other statuses distinguish missing captions, a requested caption language that is unavailable, unavailable or invalid videos, empty responses that could not be classified, parse failures, and request failures. Non-available records have zero segments. The `overview` and `segments` dataset views are available from the Output tab.

Here is an abbreviated excerpt from a successful run in automatic mode. `requestedLocale` records the request locale; `captionLanguage` is populated only for an explicit language selection that matched a YouTube track.

```json
{
  "videoId": "UF8uR6Z6KLc",
  "url": "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
  "sourceUrl": "UF8uR6Z6KLc",
  "sourceType": "video",
  "market": "US",
  "requestedLocale": "en",
  "status": "available",
  "source": "youtube_web_get_panel",
  "totalChapters": 5,
  "totalSegments": 110,
  "chapters": [
    { "title": "Chapter 1: Intro", "segmentStartIndex": 0 },
    { "title": "Chapter 2: College", "segmentStartIndex": 13 }
  ],
  "segments": [
    {
      "index": 1,
      "chapter": "Chapter 1: Intro",
      "timestamp": "0:07",
      "startSeconds": 7,
      "text": "This program is brought to you by Stanford University."
    }
  ],
  "extractedAt": "2026-10-20T01:44:01.295Z"
}
```

With `captionLanguage: "es"` and `includeSubtitles: true`, available records contain `captionLanguage`, `captionTrackName`, `captionSource`, `startMilliseconds`, `durationMilliseconds`, `srt`, `vtt`, and `subtitleTiming: "source_milliseconds"`. In automatic mode the transcript-panel path reports whole-second segment starts and, when subtitles are requested, `subtitleTiming: "inferred_end_times"`; inferred ends use later segment starts and a three-second final cue. `subtitleTruncated` indicates whether a size or cue cap shortened either export.

### Pricing

The Actor currently charges the configured `transcript-extracted` event for every successful transcript, including explicit caption-language requests. An Actor-start event is also charged according to the Store pricing configuration and run memory. Current event rates are shown on the Store page and in the pricing section of the Apify Console. Videos without a returned transcript are not charged a transcript event.

### Limits and tips

- Videos must be reachable and expose captions through YouTube's web transcript interface. Missing captions are not synthesized from audio.
- Channel and playlist expansion follows YouTube's current browse continuation and stops at `maxItems`, 100 pages per source, 150 discovery requests total, 50 source URLs, or 45 seconds. If expansion stops early, `RUN_SUMMARY` reports that it was truncated and lists remaining source URLs.
- `captionLanguage` selects a matching YouTube caption track and prefers manual over auto-generated captions. Successful records report the selected track's actual language and source.
- Explicit language requests use YouTube timedtext cue starts and durations in milliseconds. Automatic transcript-panel records retain whole-second start times.
- Set `includeChapters: false` to avoid the additional chapter request in exact-language mode while preserving the selected caption language and exact segment timings. In automatic mode this only omits the chapter fields from output.
- On Apify, channel and playlist discovery and explicit language requests use country-matched residential egress. These requests are response-capped and page-capped; automatic transcript-panel extraction continues to use datacenter egress unless a market override is supplied.
- Use `includeFullText: true` and `includeSegments: false` when you only need joined text. Keep segments enabled when you need timestamps or chapters.
- Use an explicit `captionLanguage` with `includeSubtitles` when source-exact SRT or WebVTT cue timing is useful. Automatic mode's subtitle ends remain estimates.
- The Actor applies bounded request sizes, retries, concurrency, and run time to keep batches predictable. If a run stops before all selected videos are processed, check the run summary and dataset for completed records. The summary includes up to 2,000 remaining accepted inputs and reports the full remaining count.

### Support

Use the Issues tab on the Store page to report a problem. Include the run ID and an example video URL so the issue can be reproduced.

# Actor input Schema

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

Video URLs or 11-character IDs, playlist URLs, and channel URLs. Up to 10,000 entries; playlists and channel Videos tabs expand up to maxItems.

## `maxItems` (type: `integer`):

Maximum videos processed in this run.

## `captionLanguage` (type: `string`):

Select a verified YouTube caption track by BCP-47 code (for example en or es-ES). The Actor prefers manual captions over auto-generated captions in that language, returns the actual track language and name, and returns language_unavailable if none matches. Auto keeps the existing transcript behavior.

## `preferredLanguage` (type: `string`):

Compatibility input for older integrations. This only hints the UI locale and does not verify or select a caption language.

## `proxyCountry` (type: `string`):

Override the country context for all videos. Automatic uses URL market hints.

## `includeFullText` (type: `boolean`):

Include the transcript joined into one string.

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

Include timestamped segments.

## `includeSubtitles` (type: `boolean`):

Include SRT and WebVTT. Explicit captionLanguage uses YouTube source cue timings in milliseconds; automatic mode uses inferred end times.

## `includeChapters` (type: `boolean`):

Include chapter titles. In exact-language mode this makes an extra YouTube request; automatic mode already gets chapters with the transcript.

## `diagnosticFallback` (type: `boolean`):

Fetch a watch page once to classify an empty response.

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

Concurrent videos, from 1 to 15.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
    "https://www.youtube.com/shorts/ppnJUVA1hsU"
  ],
  "maxItems": 100,
  "captionLanguage": "auto",
  "preferredLanguage": "auto",
  "proxyCountry": "AUTO",
  "includeFullText": true,
  "includeSegments": true,
  "includeSubtitles": false,
  "includeChapters": true,
  "diagnosticFallback": true,
  "maxConcurrency": 15
}
```

# Actor output Schema

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

Complete dataset with every field.

## `overview` (type: `string`):

Video status, counts and full text.

## `segments` (type: `string`):

Segments and chapters per video.

## `subtitles` (type: `string`):

Optional subtitle exports; explicit caption language requests preserve source millisecond timings.

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

Processed statuses, stop reason, remaining videos and bounded channel or playlist discovery status.

# 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=UF8uR6Z6KLc",
        "https://www.youtube.com/shorts/ppnJUVA1hsU"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hypebridge/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=UF8uR6Z6KLc",
        "https://www.youtube.com/shorts/ppnJUVA1hsU",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("hypebridge/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=UF8uR6Z6KLc",
    "https://www.youtube.com/shorts/ppnJUVA1hsU"
  ]
}' |
apify call hypebridge/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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