# YouTube Transcript Scraper — Channel & Video Subtitles (`datasiphon/youtube-transcript-scraper`) Actor

Scrape full transcripts, timestamped segments, and subtitles from YouTube channels, playlists, and single videos. Pure HTTP Innertube engine, zero headless browser, ultra-fast, multi-language & translation support.

- **URL**: https://apify.com/datasiphon/youtube-transcript-scraper.md
- **Developed by:** [Kashif Ali](https://apify.com/datasiphon) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 transcript scrapeds

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

> **Extract full video transcripts, timestamped segments, and SRT/VTT subtitles from any YouTube channel, playlist, or individual video.**\
> Built with a pure HTTP Innertube RPC engine — **zero heavy browser overhead**, runs on **256 MB RAM**, and extracts at **lightning speed**.

***

### 🚀 Why Use This YouTube Transcript Scraper?

Existing transcript scrapers on the market frequently fail:

- ❌ **Incomplete Channel Scrapes**: Most scrapers trust the channel's curated Videos tab and silently miss uploads a channel has hidden from it — plus Shorts and past streams.
- ❌ **Fragile to Blocks**: One IP block or a burst of 404s and the run dies mid-channel.

#### 🌟 What Makes This Scraper Elite:

- ✅ **Truly Complete Channel Coverage**: Discovery merges four sources — curated Videos tab, Shorts tab, Streams tab, and the channel's **full uploads playlist** via the Innertube browse API — then dedupes. If a channel has it, you get it.
- ✅ **Target Type Control**: Paste links and let auto-detect classify them, or explicitly declare "this is a channel / playlist / single video" — mislabeled inputs are corrected or clearly rejected with a reason, never silently mis-scraped.
- ✅ **Complete Playlist Extraction**: All videos in any public playlist, resolved via the Innertube browse API first (immune to page soft-blocks) with an HTML fallback, preserving playlist order.
- ✅ **Single Video Support**: Instant transcript extraction for any video URL (`/watch`, `youtu.be`, `/shorts`).
- ✅ **Pure HTTP Architecture**: Powered by lightweight RPC calls (256 MB RAM, < 1.5s per video) — **93% cheaper in compute costs** than browser-based scrapers.
- ✅ **Multi-Language & Auto-Translation**: Prioritize manual captions, fall back to auto-generated speech-to-text (ASR), and translate transcripts to any target language.
- ✅ **LLM & RAG-Ready Outputs**: Emits clean prose text (no mid-sentence line breaks), timestamped segments (`start`, `duration`, `text`), and standard `.srt` / `.vtt` subtitle files.
- ✅ **Consolidated Channel Archive**: Option to generate a single Markdown knowledge base file saved directly to your Key-Value store.

***

### 📥 Input Options

| Parameter | Type | Default | Description |
|---|---|---|---|
| `startUrls` | `Array` | *(Required)* | Paste one or more YouTube links — channels, playlists, and single videos can be mixed freely. Accepted: `@handle`, `/channel/UC...`, `/c/Name`, `/user/Name`, `/playlist?list=...`, `/watch?v=...`, `youtu.be/...`, `/shorts/...`, `/live/...`, `/embed/...`, bare 11-char IDs. |
| `targetType` | `Select` | `auto` | "Auto-detect from URL" (recommended) or force `channel` / `playlist` / `video`. Forcing helps when a `watch?v=…&list=…` link should expand as a playlist instead of scraping one video. |
| `maxVideosPerUrl` | `Integer` | `0` | Cap per link; `0` scrapes **every** video. Channel discovery merges the curated Videos tab, Shorts, streams, **and the full uploads playlist** — so you always get the complete set, even when a channel hides older videos from its tab (e.g. Starter Story's tab shows 186 of 524 uploads). |
| `startDate` | `String` | *(Optional)* | For channel/playlist URLs, only discover videos published on or after this date (inclusive, `YYYY-MM-DD`). |
| `endDate` | `String` | *(Optional)* | For channel/playlist URLs, only discover videos published on or before this date (inclusive, `YYYY-MM-DD`). |
| `fetchVideoMetadata` | `Boolean` | `true` | Fetch per-video metadata (description, views, publish date, thumbnail, keywords, category, available caption languages). Disable for maximum speed on very large runs. |
| `includeShorts` | `Boolean` | `true` | When scraping a channel, also scrape transcripts for YouTube Shorts. |
| `includeLiveStreams` | `Boolean` | `true` | When scraping a channel, also scrape transcripts for past live streams. |
| `preferredLanguages` | `Array` | `["en"]` | Priority list of ISO language codes (e.g. `["en", "es", "de"]`). Falls back to available tracks if not found. |
| `preferAutoGenerated` | `Boolean` | `true` | Automatically fall back to YouTube's auto-generated speech recognition when manual subtitles are absent. |
| `translateTo` | `String` | `""` | Optional ISO language code to translate the transcript into (e.g. `"es"` for Spanish). |
| `outputFormats` | `Select` | `"all"` | Choose `"all"` (text + segments + SRT + VTT), `"plainTextOnly"`, `"segmentsOnly"`, or `"srtOnly"`. |
| `generateChannelSummaryFile`| `Boolean` | `false` | Consolidates all transcripts into a single `TRANSCRIPTS_<channel>.md` file in the Key-Value store. |
| `proxyConfiguration` | `Object` | `{ "useApifyProxy": true }` | Apify proxy configuration to bypass rate limits on massive batch runs. **Keep enabled** — without a proxy, YouTube frequently blocks transcript fetching (`IP_BLOCKED`). |
| `maxConcurrency` | `Integer` | `10` | Number of concurrent video transcripts to fetch simultaneously (1 to 50). |

> **Resilience:** Videos that fail due to blocks or transient errors are automatically re-attempted in retry rounds with fresh proxy sessions and growing backoff before being reported as `IP_BLOCKED`/`ERROR`, so blocked videos are recovered whenever possible.

***

### 📤 Output Format

Each scraped video is saved as a structured record in the default Apify Dataset:

```json
{
  "videoId": "dQw4w9WgXcQ",
  "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
  "channelName": "Rick Astley",
  "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
  "channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
  "videoType": "VIDEO",
  "hasTranscript": true,
  "language": "English",
  "languageCode": "en",
  "isAutoGenerated": false,
  "isTranslation": false,
  "text": "We're no strangers to love. You know the rules and so do I. A full commitment's what I'm thinking of...",
  "textWordCount": 384,
  "textCharacterCount": 2048,
  "durationSeconds": 213,
  "description": "The official video...",
  "viewCount": 1818112471,
  "publishDate": "2009-10-24T23:57:33-07:00",
  "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
  "keywords": ["rick astley", "never gonna give you up"],
  "category": "Music",
  "availableLanguages": ["en", "de-DE", "ja", "pt-BR", "es-419"],
  "segmentCount": 61,
  "segments": [
    {
      "start": 18.64,
      "duration": 3.24,
      "text": "We're no strangers to love"
    },
    {
      "start": 22.64,
      "duration": 4.32,
      "text": "You know the rules and so do I"
    }
  ],
  "srt": "1\n00:00:18,640 --> 00:00:21,880\nWe're no strangers to love\n\n2\n00:00:22,640 --> 00:00:26,960\nYou know the rules and so do I",
  "vtt": "WEBVTT\n\n00:00:18.640 --> 00:00:21.880\nWe're no strangers to love\n\n00:00:22.640 --> 00:00:26.960\nYou know the rules and so do I",
  "status": "SUCCESS",
  "errorMessage": null,
  "scrapedAt": "2026-09-20T16:30:00.000Z"
}
```

If a video does not have subtitles (e.g., ambient music or captions disabled by the creator), the actor records `hasTranscript: false` with the matching `status` **without failing the run**. Only when **none** of the provided URLs resolve to at least one video does the run fail explicitly.

#### Status Reference

Every dataset record carries exactly one `status`:

| Status | Meaning | Fails the run? |
|---|---|---|
| `SUCCESS` | Transcript extracted successfully. | No |
| `NO_TRANSCRIPT_AVAILABLE` | No caption tracks exist, or none match `preferredLanguages` while `preferAutoGenerated: false`. | No |
| `TRANSCRIPTS_DISABLED` | The creator disabled captions for this video. | No |
| `VIDEO_UNAVAILABLE` | Video is private, deleted, or unavailable. | No |
| `AGE_RESTRICTED` | Video is age-restricted; transcripts require authentication. | No |
| `IP_BLOCKED` | YouTube blocked the request (after one automatic retry). Enable Apify **RESIDENTIAL** proxies for large runs. | No |
| `ERROR` | Unexpected retrieval failure — see `errorMessage`. | No |

#### Notes on Output

- `channelUrl` / `channelId` are populated from channel metadata whenever the video is discovered via a channel or playlist; for single-video targets the actor enriches them via oEmbed when available.
- `durationSeconds` comes from video metadata when known, otherwise it is approximated from the last transcript timestamp.
- `segments`, `srt`, and `vtt` are included according to the `outputFormats` setting (`all` emits everything; `plainTextOnly` omits all three).
- Cue tags such as `[Music]`, `[Applause]`, and `[Laughter]` are stripped from text, segments, SRT, and VTT.
- `availableLanguages` lists every caption language YouTube offers for the video — re-run with one of them via `preferredLanguages` if the default pick was wrong.
- Set `fetchVideoMetadata: false` to skip the metadata round-trip per video (text/segments/SRT/VTT are unaffected; metadata fields become `null`).

***

### 💻 Integrations & API Usage

#### Python (Apify Client)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

## Scrape an entire YouTube channel
run_input = {
    "startUrls": ["https://www.youtube.com/@veritasium"],
    "maxVideosPerUrl": 50,
    "includeShorts": True,
    "outputFormats": "all"
}

run = client.actor("DataSiphon/youtube-transcript-scraper").call(run_input=run_input)

## Fetch dataset items
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"[{item['title']}] ({item['language']}): {item['textWordCount']} words")
```

#### Node.js (Apify Client)

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

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

const run = await client.actor('DataSiphon/youtube-transcript-scraper').call({
  // Complete uploads playlist of the "Google for Developers" channel.
  // Tip: replace the "UC" prefix of any channel ID with "UU" to get its uploads playlist.
  startUrls: ['https://www.youtube.com/playlist?list=UU_x5XG1OV2P6uZZ5FSM9Ttw'],
  preferredLanguages: ['en'],
  outputFormats: 'all',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Scraped ${items.length} video transcripts.`);
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/DataSiphon~youtube-transcript-scraper/runs?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": ["https://www.youtube.com/@hubermanlab"],
    "maxVideosPerUrl": 10
  }'
```

***

### ❓ Frequently Asked Questions

##### Can it scrape private or unlisted videos?

It can scrape **unlisted** videos if you provide the direct URL. Private videos or videos behind a member-only paywall cannot be scraped without authentication cookies.

##### What if a channel has thousands of videos?

Set `maxVideosPerUrl: 0` to scrape without limits. The Innertube continuation loop will paginate through thousands of uploads seamlessly while consuming under 256 MB of RAM.

##### Are auto-generated subtitles supported?

Yes. If manual human subtitles were not uploaded by the creator, the scraper automatically grabs YouTube's speech-to-text transcript (`preferAutoGenerated: true`).

##### How does translation work?

Set `translateTo: "es"` (or any valid language code). The scraper uses YouTube's server-side translation track to return the transcript in your target language.

***

### 📄 License & Terms

This actor is intended for personal research, accessibility, and AI training applications. Please respect YouTube's Terms of Service and copyright guidelines for content reuse.

***

### Pricing & cost estimator

Pay-per-event: **$3.00 per 1,000 transcripts (videos without a transcript or blocked videos are not billed)**. You are charged only for rows that contain data; empty or failed targets are free. A 100-item run typically costs well under $0.50 in total. Use `maxItems` / the per-link cap to control spend.

### Example output (real run)

```json
{
  "videoId": "P14HA83uNJE",
  "videoUrl": "https://www.youtube.com/watch?v=P14HA83uNJE",
  "title": "a video to watch if you're ambitious and in your 20s or 30s",
  "channelName": "Alex Hormozi",
  "channelId": "UCUyDOdBWhC1MCxEjC46d-zw",
  "channelUrl": "https://www.youtube.com/channel/UCUyDOdBWhC1MCxEjC46d-zw",
  "description": "Download your free scaling roadmap here: https://www.acquisition.com/roadmap?el=yt-alex-ma…",
  "viewCount": 471126,
  "publishDate": "2026-09-17T06:00:39-07:00",
  "thumbnail": "https://i.ytimg.com/vi_webp/P14HA83uNJE/maxresdefault.webp",
  "keywords": [
    "Alex Hormozi",
    "Alex Hormozi Business Tips"
  ],
  "category": "Entertainment",
  "availableLanguages": [
    "en"
  ],
  "videoType": "VIDEO",
  "hasTranscript": true,
  "language": "English (auto-generated)",
  "languageCode": "en",
  "isAutoGenerated": true,
  "isTranslation": false,
  "text": "Just got off the phone with a friend of mine who's competing in a fitness thing and she di…",
  "textWordCount": 1796,
  "textCharacterCount": 9412,
  "segmentCount": 282,
  "durationSeconds": 531,
  "status": "SUCCESS",
  "scrapedAt": "2026-10-01T06:51:40.175354+00:00",
  "segments": [
    {
      "start": 0,
      "duration": 3.24,
      "text": "Just got off the phone with a friend of"
    },
    {
      "start": 1,
      "duration": 5.48,
      "text": "mine who's competing in a fitness thing"
    }
  ],
  "srt": "1\n00:00:00,000 --> 00:00:03,240\nJust got off the phone with a friend of\n\n2\n00:00:01,000 --…",
  "vtt": "WEBVTT\n\n\n00:00:00.000 --> 00:00:03.240\nJust got off the phone with a friend of\n\n00:00:01.0…"
}
```

### Limitations

Videos with captions disabled return a free row with `hasTranscript: false`. YouTube sometimes blocks cheap IPs; blocked videos are retried through a residential proxy automatically (the only extra cost).

### No login, no cookies

This actor only reads public YouTube watch pages and caption tracks. It never asks for a cookie, password or account and does not access private data. Make sure your use of the scraped data complies with the source site's terms and applicable law (GDPR/CCPA for personal data).

***

### YouTube transcript scraper — FAQ & use cases

**How do I get a YouTube transcript with an API?** Run this Actor via the Apify API with video, playlist or channel URLs and fetch the dataset as JSON, CSV or Excel.
**Can it scrape subtitles and captions in bulk?** Yes — whole channels, playlists and Shorts, with `maxVideosPerUrl` to control cost.
**Which formats?** Clean plain text, timestamped segments (`start`, `duration`, `text`), **SRT** and **VTT**; translate to any language with `translateTo`.
**Does it cache transcripts?** Yes — repeat requests are served from a cache (default `maxCacheAgeDays: 90`; set 0 for always-fresh). Cached rows carry `cached`, `fetched_at` and `cacheAgeDays`; a 30-video re-run finishes in seconds instead of a minute.
**Is it good for LLM / RAG?** Yes — plain-text output and a Markdown channel knowledge base file.
**Pricing:** pay per event, **$3 per 1,000 transcripts**; videos without captions or blocked videos are free. Blocked videos are retried through a residential proxy automatically.
**Use cases:** AI and RAG datasets · content repurposing · SEO and keyword research from video text · accessibility and subtitles · research and archiving.

### YouTube transcript API, subtitle downloader & SRT/VTT

A reliable YouTube transcript API and subtitle downloader: retrieve transcripts and subtitles for YouTube videos, with timed transcript segments in JSON, plus SRT and VTT captions in bulk — extract transcripts from videos, channels and playlists, then export.

### Related scrapers by the same author

[YouTube Email Scraper](https://apify.com/datasiphon/youtube-email-scraper) · [Reddit Scraper](https://apify.com/datasiphon/reddit-scraper) · [LinkedIn Jobs Scraper](https://apify.com/datasiphon/linkedin-jobs-scraper) · [Airbnb Scraper](https://apify.com/datasiphon/airbnb-scraper) · [Amazon Product Scraper](https://apify.com/datasiphon/amazon-product-scraper)

# Actor input Schema

## `targetType` (type: `string`):

Pick what your links point to. "Auto-detect" figures it out from each URL (recommended). Force a type only if YouTube serves an unexpected page shape.

## `startUrls` (type: `array`):

Paste one or more YouTube links. Mixing channels, playlists, and videos in one run is fine. Accepted formats: youtube.com/@handle, /channel/UC..., /c/Name, /user/Name, /playlist?list=..., /watch?v=..., youtu.be/..., /shorts/..., /live/..., /embed/..., or a bare 11-character video ID. Duplicates across links are scraped once.

## `maxVideosPerUrl` (type: `integer`):

Hard cap per link: 0 scrapes every single video on the channel/playlist (can be thousands). A channel's total = its curated Videos tab + all Shorts + all streams + anything else in its uploads; you always get the complete set.

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

Skip videos published before this date (YYYY-MM-DD, UTC). Leave empty for no lower bound. Dates come from video metadata where available.

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

Skip videos published after this date (YYYY-MM-DD, UTC). Leave empty for no upper bound. Videos with unknown dates are always kept, never dropped.

## `includeShorts` (type: `boolean`):

Also scrape YouTube Shorts found on the channel. They are always included if they appear in the uploads playlist.

## `includeLiveStreams` (type: `boolean`):

Also scrape completed live streams (VODs) from the channel's Streams tab.

## `preferredLanguages` (type: `array`):

ISO codes tried in order (e.g. en, es, de). The best available track is chosen: manual captions always beat auto-generated for the same language. If none match, the original language is returned and availableLanguages in the output shows every option YouTube has.

## `preferAutoGenerated` (type: `boolean`):

When a video has no human-made subtitles, fall back to YouTube's automatic speech recognition. Turning this off will mark caption-less videos as NO\_TRANSCRIPT\_AVAILABLE instead.

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

ISO code of the language you want everything in (e.g. es, fr, de). Uses YouTube's server-side translation. Leave empty to keep the original language. isTranslation: true in the output marks translated items.

## `outputFormats` (type: `string`):

Which transcript shapes to write into each dataset item.

## `fetchVideoMetadata` (type: `boolean`):

Enrich each item with description, view count, publish date, thumbnail, keywords, category, and all available caption languages. Disable for maximum speed on huge channels.

## `generateChannelSummaryFile` (type: `boolean`):

Writes TRANSCRIPTS\_<channel>.md into the Key-Value store: a table of contents plus every transcript in one document. Handy for humans and for importing into Notion/Obsidian.

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

Strongly recommended: Apify Proxy. YouTube rate-limits datacenter IPs aggressively — without a proxy, large channels often fail with IP\_BLOCKED. For channels with 100+ videos, RESIDENTIAL proxies give the best results.

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

How many videos to fetch simultaneously (1–50). Higher is faster; 10 is a safe default. If you see IP\_BLOCKED statuses, lower this and/or add residential proxies.

## `fallbackProxyConfiguration` (type: `object`):

Cheap proxy is tried first; videos YouTube blocks are retried through this proxy. Default: Apify Residential. Set to null to disable.

## `maxCacheAgeDays` (type: `integer`):

Transcripts fetched within this many days are returned from the cache (faster, no proxy). Rows show cached, fetched\_at and cacheAgeDays. Set 0 to always fetch fresh.

## Actor input object example

```json
{
  "targetType": "auto",
  "startUrls": [
    {
      "url": "https://www.youtube.com/@starterstory"
    }
  ],
  "maxVideosPerUrl": 100,
  "startDate": "",
  "endDate": "",
  "includeShorts": true,
  "includeLiveStreams": true,
  "preferredLanguages": [
    "en"
  ],
  "preferAutoGenerated": true,
  "translateTo": "",
  "outputFormats": "all",
  "fetchVideoMetadata": true,
  "generateChannelSummaryFile": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 10,
  "fallbackProxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxCacheAgeDays": 90
}
```

# Actor output Schema

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

Dataset containing all extracted transcripts, segments, and metadata

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

Key-value store containing optional consolidated channel transcript markdown documents

# 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 = {
    "startUrls": [
        {
            "url": "https://www.youtube.com/@starterstory"
        }
    ],
    "fallbackProxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datasiphon/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 = {
    "startUrls": [{ "url": "https://www.youtube.com/@starterstory" }],
    "fallbackProxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("datasiphon/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 '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/@starterstory"
    }
  ],
  "fallbackProxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call datasiphon/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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