# YouTube Transcript Scraper — Text, Timestamps, Translations (`architekture/youtube-transcript-scraper`) Actor

YouTube transcripts, worldwide, from youtube.com: transcript text, timestamped segments, caption language, auto-generated flag, available languages, translations, title, channel, duration and view count, by video URL or ID. Pay per result. No login. Videos without captions are not charged.

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

from $4.00 / 1,000 transcripts

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 — Text, Timestamps, Translations

**Recorded run: 1 transcript from 1 video in 5 seconds** (2026-10-22, build 0.0.11, run `b4OEXuL1cdvWSAUz8`). A bounded canary sample, not a full-catalogue benchmark.

architek.earth — an independent data studio. Pay-per-result scrapers with recorded runs, published canaries and stable schemas, built for people and AI agents.

YouTube video transcripts, timestamped caption segments and translations: give it video URLs or IDs, get one row per video with the transcript text, `start`/`duration` segments, caption language, auto-generated flag, title and channel.

| Source | Market | From | Standout fields |
|---|---|---|---|
| YouTube (youtube.com) | Worldwide, any caption language | $4.00 / 1,000 transcripts | `transcriptText`, `segments`, `isAutoGenerated`, `availableLanguages` |

### ✅ Why choose this scraper

#### YouTube transcript text and timestamps in one row

`transcriptText` holds the whole transcript as one string; `segments` holds `[{start, duration, text}]` in seconds for subtitles, chapters and quote links. The canary video returned 427 segments.

#### Translate YouTube captions into another language

`translateTo` requests YouTube's own caption translation; translated rows set `isTranslated: true`, `language` to the target and `sourceLanguage` to the original. A failed translation returns `translation_unavailable`, never original-language text.

#### Pick manual or auto-generated subtitles by language

`languages` is an ordered preference list (`en` also matches `en-GB`), `preferManualCaptions` puts uploader captions before auto-generated ones, and `availableLanguages` lists every caption track YouTube returned (65 on the canary video).

#### No charge for videos without a transcript

Only rows with `status: "ok"` trigger an event. Videos with no captions, the wrong language, private, removed, age-restricted or blocked videos come back as rows with `status` and `message`, uncharged.

#### Measured on a schedule

A canary task fetches the same TED talk on the live site every day and records rows, inputs and seconds; the hero line above is its latest green run.

### ⚠️ Worth knowing up front

- This actor reads YouTube's caption tracks. It does not run speech-to-text on audio: a video with no manual or auto-generated captions returns `status: "no_captions"`.
- Auto-generated captions are YouTube's speech recognition, errors included, and usually lack punctuation. `isAutoGenerated: true` marks them.
- Members-only, private and age-restricted videos are not supported; the actor does not log in. They return an uncharged `login_required`, `age_restricted` or `unavailable` row, depending on YouTube's response.
- Live links are accepted as video URLs, but live captions are not collected continuously. Replay captions depend on what YouTube makes available.
- Video metadata is limited to `title`, `channelName`, `channelId`, `durationSeconds`, `viewCount` and `isLiveContent`. No comments, likes or descriptions.
- Each video gets 3 attempts, each refusal (an HTTP error or a challenge / captcha page) opening a new session; a video that still fails returns `status: "blocked"`. After 3 consecutive blocked videos the run stops scheduling new ones with `SOURCE_BLOCKED`. Each new translation session waits 60 seconds before its first translated caption; allow a run timeout of at least 300 seconds for translations.
- A run stopped by its timeout, your spending limit or repeated blocks keeps what it delivered; `RUN_SUMMARY.unprocessed` counts the videos not attempted.
- Every processed video gets one row whose `status` says what happened, and an unrecognised `videos` entry gets an `invalid_input` row. Input the run cannot use (a wrong-typed field, no `videos`, an unavailable proxy group) writes one free status row with `recordType: "status"` and `status: "INVALID_INPUT"`. An exhausted preview allowance and stops for time, budget or blocks write no row; the reason is in the run's status message and the `RUN_SUMMARY` record.

### ⚡ Try the example

Each Apify account gets 20 lifetime free preview attempts on this actor: up to 10 input videos per attempt, one worker, original-language captions only, no transcript charges. Missing transcripts and blocked attempts still count. After the twentieth, preview runs stop with `PREVIEW_LIMIT`; they never switch to paid collection.

Open the actor's input page, switch to JSON, paste this and start the run:

```json
{
  "videos": ["https://www.youtube.com/watch?v=iG9CE55wbtY"],
  "languages": ["en"],
  "preview": true
}
```

For paid collection set `"preview": false`; add `"translateTo": "fr"` (or another language code) for a translated transcript at $0.010.

### ⚙️ Input

| Parameter | Type | Default | Description |
|---|---|---|---|
| `videos` | array | required | Video URLs (watch, youtu.be, Shorts, embed, live) or 11-character IDs. Up to 5,000 per run; duplicates are fetched once. |
| `languages` | array | `["en"]` | Preferred caption languages in order, as ISO codes. An empty list takes the first available track. |
| `preferManualCaptions` | boolean | `true` | Within a language, uploader captions before auto-generated ones. |
| `fallbackToAnyLanguage` | boolean | `true` | If no preferred language exists, return the first available track instead of `language_unavailable`. |
| `translateTo` | string | — | YouTube translation target such as `en` or `fr`. Unsupported targets return `translation_unavailable`. Not available in preview. |
| `includeSegments` | boolean | `true` | Add timestamped `segments`. At least one of text or segments must be on. |
| `includeText` | boolean | `true` | Add `transcriptText`. |
| `maxConcurrency` | integer | `1` | Videos fetched in parallel (1–10). Higher values open separate sessions, each with its own translation wait. |
| `proxyConfiguration` | proxy | Apify RESIDENTIAL | Proxy settings. Residential is the default used in recorded runs. |
| `preview` | boolean | `false` | Use one of 20 lifetime free attempts: up to 10 videos, original-language captions only. |
| `feedback` | string | — | Optional note for the maintainers. It is logged and read by a human, and it never changes output. |

### 🧱 Stable fields

These top-level fields keep the same name and the same kind of value in every release. Fields are only ever added, never renamed or removed, so an n8n, Make, Zapier or spreadsheet pipeline can bind to them.

| Field | Type | Meaning |
|---|---|---|
| `videoId` | string, nullable | 11-character YouTube ID; null only on `invalid_input` rows. |
| `url` | string, nullable | Canonical watch URL; null on `invalid_input` rows. |
| `input` | string, nullable | The `videos` entry that produced the row; null on the `INVALID_INPUT` status row. |
| `status` | string | `ok`, `no_captions`, `language_unavailable`, `translation_unavailable`, `unavailable`, `age_restricted`, `login_required`, `blocked`, `error` or `invalid_input`; `INVALID_INPUT` on the run-level status row. Only `ok` is charged. |
| `message` | string, nullable | Reason when `status` is not `ok`. |
| `title` / `channelName` / `channelId` | string, nullable | Video title, channel name and channel ID. |
| `durationSeconds` / `viewCount` | number, nullable | Video length in seconds and view count. |
| `isLiveContent` | boolean, nullable | YouTube's live-content flag for the video. |
| `language` / `languageName` | string, nullable | Language of the returned transcript (the target when translated). |
| `isAutoGenerated` | boolean, nullable | True when YouTube's speech recognition made the captions. |
| `isTranslated` | boolean | True when translation was applied; false when the selected track already matched `translateTo`. |
| `availableLanguages` | array | Caption tracks YouTube returned: `{language, languageName, isAutoGenerated}`. |
| `transcriptText` | string, nullable | Whole transcript as one string; null when disabled or not `ok`. |
| `segments` | array, nullable | `[{start, duration, text}]` in seconds; null when disabled or not `ok`. |
| `segmentCount` | number | Number of segments; 0 when not `ok`. |
| `scrapedAt` | string | UTC timestamp. |

Filter on `status == "ok"` for paid transcript rows; only the run-level `INVALID_INPUT` row carries `recordType: "status"`. Translated rows also carry `sourceLanguage`, the original caption language; it is absent on original-language rows. Other fields are extras, not part of the contract. To have one pinned, say so in `feedback`.

### 📦 Output example

Abridged real row from run `b4OEXuL1cdvWSAUz8` on 2026-10-22; values are a historical snapshot. The full row has 427 segments and 65 entries in `availableLanguages`.

```json
{
  "videoId": "iG9CE55wbtY",
  "url": "https://www.youtube.com/watch?v=iG9CE55wbtY",
  "status": "ok",
  "message": null,
  "title": "Do schools kill creativity? | Sir Ken Robinson | TED",
  "channelName": "TED",
  "channelId": "UCAuUUnT6oDeKwE6v1NGQxug",
  "durationSeconds": 1203,
  "viewCount": 25056294,
  "isLiveContent": false,
  "language": "en",
  "languageName": "English",
  "isAutoGenerated": false,
  "isTranslated": false,
  "availableLanguages": [
    {"language": "en", "languageName": "English", "isAutoGenerated": false},
    {"language": "en", "languageName": "English (auto-generated)", "isAutoGenerated": true}
  ],
  "transcriptText": "Good morning. How are you? (Audience) Good. It's been great, hasn't it? ...",
  "segments": [
    {"start": 27.103, "duration": 2.575, "text": "Good morning. How are you?"},
    {"start": 29.702, "duration": 1.403, "text": "(Audience) Good."}
  ],
  "segmentCount": 427,
  "scrapedAt": "2026-10-22T03:01:33Z"
}
```

This actor has no separate status row. An uncharged row for a video without captions looks like this (abridged, run `0SEq5FFyzSLPaVRHq`, 2026-10-15):

```json
{
  "videoId": "TtIrFvWoY8E",
  "status": "no_captions",
  "message": "This video has no captions (the uploader disabled them or none were generated).",
  "transcriptText": null
}
```

### 🧠 Advanced usage

#### Get transcripts for a whole YouTube channel or playlist

Feed the video URLs from any channel or playlist video-list actor into `videos`, up to 5,000 per run; duplicates are fetched once.

#### Require English captions only

Set `languages: ["en"]`, `fallbackToAnyLanguage: false` and leave `translateTo` empty. Videos without an English track return `language_unavailable` and are not charged.

#### Retry only the YouTube videos that failed

Filter the dataset for `status == "blocked"` or `"error"` and rerun those `videoId` values later; they were not charged.

#### Check a bulk transcript run is complete

Read the `RUN_SUMMARY` record (`status`, `transcripts`, `byStatus`, `chargedEvents`, `statusRows`, `unprocessed`) before marking an import complete. Run statuses: `COMPLETE`, `PARTIAL`, `BLOCKED`, `SOURCE_BLOCKED`, `BUDGET_LIMIT`, `TIME_LIMIT`, `INVALID_INPUT`, `PREVIEW_LIMIT`, `PREVIEW_UNAVAILABLE`, `FAILED`. A run whose spending limit covers every requested video exactly ends `COMPLETE`; `BUDGET_LIMIT` means at least one video was left undelivered. The run's status message is `Done: N rows, M details, K status rows (STATUS; outcome)`: N transcripts delivered, M of them translations, K free rows with another `status`, then the plain-language outcome.

### 🔌 Integrations

Results land in a dataset you can export as JSON, CSV or Excel. They can also flow to Google Sheets, Make, Zapier or n8n, or to a webhook when a run finishes. The Apify Scheduler runs it on a timetable. A daily run over a channel's newest video URLs picks up each upload's captions once YouTube publishes them. Copy-paste code in Python, Node, curl and n8n: [architek-earth/examples/youtube-transcript-scraper](https://github.com/architek-earth/examples/tree/main/youtube-transcript-scraper).

### 💸 Pricing

Pay per result. Platform and proxy usage are included. Rows with any status other than `ok` and failed requests are free. If the platform restarts a run, videos already listed in its `PROGRESS` record are skipped and not charged again; a video delivered just before an abrupt stop may not be in `PROGRESS` yet and can be charged again. A new run fetches and charges every input again.

| Event | Price | What it covers |
|---|---|---|
| Free preview | $0 | 20 lifetime attempts per account; up to 10 videos each, original-language captions only. |
| `transcript` | $4.00 / 1,000 transcripts | One delivered row with `status: "ok"` and `isTranslated: false`. |
| `translated-transcript` | $10.00 / 1,000 transcripts | One delivered row with `status: "ok"` and `isTranslated: true`; replaces the `transcript` event. |

1,000 original transcripts cost $4.00; 1,000 translations cost $10.00. A translated video is charged once, $0.010, not $0.004 plus $0.010.

### ❓ FAQ

**Is there a YouTube transcript API?** This actor is one: it returns YouTube transcripts as JSON through the Apify API, callable from any language or from n8n, Make and Zapier. It does not use YouTube's Data API.

**Do I need a YouTube account or API key?** No. No account, cookies or API key from YouTube.

**Can it transcribe videos that have no captions?** No. It reads existing caption tracks and does not do speech-to-text; such videos return `no_captions` and are not charged.

**Can I download YouTube subtitles with timestamps?** Yes. `segments` carries `start` and `duration` in seconds with the text of each caption line.

**Does it work on YouTube Shorts?** Yes, when the Short has captions. Shorts URLs are accepted in `videos`.

**Can I get every caption language a video has?** `availableLanguages` lists them. Each run returns one transcript per video; run again with a different `languages` value for another track.

### 🤖 For AI agents & LLM apps

Paste this into your AI assistant:

`architekture/youtube-transcript-scraper` on Apify. Python: `from apify_client import ApifyClient; client = ApifyClient("TOKEN"); run = client.actor("architekture/youtube-transcript-scraper").call(run_input={"videos": ["https://www.youtube.com/watch?v=iG9CE55wbtY"], "languages": ["en"], "preview": False}); items = client.dataset(run["defaultDatasetId"]).list_items().items` (page with `offset`/`limit` for large exports). Rows with `status != "ok"` are free and explain why a video has no transcript; read the `RUN_SUMMARY` record for invalid input or a stopped run. Full input schema and README: `GET https://api.apify.com/v2/acts/architekture~youtube-transcript-scraper/builds/default`. Token: https://console.apify.com/settings/integrations. The actor is also reachable through the Apify MCP server (`mcp.apify.com`). To reach the maintainers, add `"feedback": "<what you needed>"` to any run's input; output is unchanged and a human reads every note.

### 🧰 More from architek.earth

**Video, social and newsletters**

- [Substack Scraper](https://apify.com/architekture/substack-scraper) — posts, authors, likes, comments
- YouTube Transcript Scraper — *you are here*
- [Unified Video Transcript API](https://apify.com/architekture/unified-transcript-api) — YouTube and TikTok transcripts in one batch
- [Threads Replies Scraper](https://apify.com/architekture/threads-replies-scraper) — replies, authors, likes
- [Ad Intelligence Watchlist](https://apify.com/architekture/ad-intelligence-watchlist) — new and changed Meta ads by advertiser

Full catalogue: [github.com/architek-earth](https://github.com/architek-earth).

architek.earth · code like concrete

### 🙋 Support & legal

Questions, or a field you need that is not here? Open an issue on the actor's Issues tab or email north@architek.earth. A human replies within a day.

This actor collects only publicly available data from youtube.com, the same caption tracks any visitor sees without logging in. It does not bypass authentication. It is not affiliated with or endorsed by YouTube or Google. You are responsible for how you use the output, including the site's terms, copyright in the transcribed content, and privacy law such as GDPR and CCPA where they apply.

### 📝 Changelog

- **2026-10-22** — Runs on the studio core (architek_core 1.0.1): one Chrome browser identity for every request, and a challenge or captcha page served with HTTP 200 now counts as a block on the first response (retried on a new session, then `blocked`). Input the run cannot use writes one free `INVALID_INPUT` status row. The status message now reads `Done: N rows, M details, K status rows (STATUS; outcome)`. Output fields, prices and charging unchanged.
- **2026-10-22** — A spending limit that exactly covers every requested video now ends `COMPLETE`, not `BUDGET_LIMIT`; only a video left uncharged and undelivered stops the run.
- **2026-10-22** — Pricing guard: before any request or charge, the run refuses to start (`FAILED`, nothing collected or charged) unless its pay-per-event pricing is exactly `transcript` $0.004 and `translated-transcript` $0.010.
- **2026-10-22** — Every run's status message now ends with `Done: N rows, M details, K status rows (STATUS)`; `RUN_SUMMARY.statusRows` added.
- **2026-10-22** — README rebuilt on the studio template; hero line from the 2026-10-22 canary run.
- **2026-10-19** — Clarified the difference from the mixed YouTube/TikTok actor, corrected transcript cost examples, and qualified caption availability. Prices and extraction code unchanged.
- **2026-10-15** — Made the first example a free preview, added an explicitly priced translation example, and documented the live mixed-event billing check. Clarified live-link limitations and matching-language behavior.
- **2026-10-15** — Split billing by delivered output: $4.00 / 1,000 original transcripts and $10.00 / 1,000 translations. Successful paid results select one event; matching-language requests stay at the original price, and failures and previews remain uncharged. Added event counts to the run summary.
- **2026-10-15** — Enabled automatic 60-second translation-session preparation and one-worker defaults. Added a deadline check before preparation so an insufficient timeout stops cleanly before another caption fetch or cooldown. Original-language requests have no translation delay.
- **2026-10-15** — Recorded four translated transcripts across three experiments using a private 60-second cooldown: German to English and English to French, including a two-video batch reusing one warmed session. Preserved a sanitized translated response as a regression fixture.
- **2026-10-15** — Added fail-closed preview quota enforcement (one hosted preview verified with zero transcript events), repeated-block batch stopping, explicit residential defaults for API inputs, and safeguards against empty paid output and uncertain billing acknowledgements.
- **2026-10-15** — Private live validation: recorded manual English/German and automatic German transcripts, captionless Short and unavailable-video handling. Replaced illustrative output with real rows and added sanitized recorded regression fixtures.
- **2026-10-15** — 1.0: video URLs and IDs, language preference with manual-first selection, YouTube caption translation, text and timestamped segments, per-video status rows, charge only on `ok`, session and IP rotation on blocks, clean stops at the charge limit and run timeout.

# Actor input Schema

## `videos` (type: `array`):

YouTube video URLs or 11-character video IDs. Accepts watch, youtu.be, Shorts, embed and live links. Duplicates are fetched once.

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

Caption languages in order of preference, as ISO codes (en, es, pt-BR, zh-Hans). 'en' also matches en-US and en-GB. Default: en. Set an empty list to take the video's first available track.

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

Within a language, use uploader-provided captions before YouTube's auto-generated ones. Turn off to prefer auto-generated.

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

If no preferred caption language exists, return an available track instead of language_unavailable. The output language identifies the actual returned track.

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

YouTube translation target, such as en or fr. Translation automatically prepares each new session with a 60-second cooldown; later videos reuse it. Allow at least 300 seconds run timeout for retries. Unsupported targets return translation_unavailable. A failed translation is never replaced with original-language text. Successful translated results cost $0.010 each, replacing the $0.004 original event. Translation is not available in free preview.

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

Add 'segments': a list of {start, duration, text} in seconds.

## `includeText` (type: `boolean`):

Add 'transcriptText': the whole transcript as one string, ready for LLMs and search.

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

Videos fetched in parallel (1-10). Default 1 reuses one warmed translation session. Higher values need separate session cooldowns and can increase blocking, memory and cost.

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

Residential proxy is the default used in recorded validation. Availability varies by session; proxy use does not eliminate blocks.

## `feedback` (type: `string`):

Tell us what you needed and did not get. Logged for human review; does not change output.

## `preview` (type: `boolean`):

20 lifetime preview attempts per Apify account; up to 10 input videos per attempt, original-language captions only, one worker. Failed upstream attempts also consume an allowance. Neither original nor translation events are charged. Allowance errors stop without paid fallback.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=iG9CE55wbtY"
  ],
  "languages": [
    "en"
  ],
  "preferManualCaptions": true,
  "fallbackToAnyLanguage": true,
  "includeSegments": true,
  "includeText": true,
  "maxConcurrency": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "preview": false
}
```

# Actor output Schema

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

One row per processed unique video. Check summary for unprocessed inputs.

## `summary` (type: `string`):

RUN_SUMMARY record: overall status and counts per row 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 = {
    "videos": [
        "https://www.youtube.com/watch?v=iG9CE55wbtY"
    ],
    "languages": [
        "en"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("architekture/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 = {
    "videos": ["https://www.youtube.com/watch?v=iG9CE55wbtY"],
    "languages": ["en"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("architekture/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 '{
  "videos": [
    "https://www.youtube.com/watch?v=iG9CE55wbtY"
  ],
  "languages": [
    "en"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call architekture/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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