# YouTube Transcripts in Bulk — whole channels, playlists (`pampadata/youtube-transcripts-bulk`) Actor

Transcripts of whole YouTube channels (no 200-video cap), playlists and video lists, with timestamps, your language or the next one available, manual vs auto-generated marked. Charged only per transcript delivered.

- **URL**: https://apify.com/pampadata/youtube-transcripts-bulk.md
- **Developed by:** [Cowboi Bebot](https://apify.com/pampadata) (community)
- **Categories:** Videos, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

Transcripts of **whole YouTube channels** (no 200-video cap: the channel's list is read to the end), **playlists** and lists of videos, in one run. Each row has the transcript **with timestamps** and as plain text, in **your language or the next one available**, and says whether the subtitles were **written by a person or auto-generated**. You pay only per transcript delivered: **a run that finds nothing costs nothing beyond Apify's start event, and a video without subtitles is never charged.**

*Versión en español más abajo.*

### Quick facts

- **What it does:** Transcripts of whole YouTube channels (no 200-video cap), playlists and video lists, with timestamps and plain text, in your language or the next one available, manual vs auto-generated marked.
- **Use it for:** text of a channel's or playlist's videos for search, analysis, summaries or AI pipelines; monitoring channels for new videos.
- **Not for:** comments or viewer data; age-restricted, private or members-only videos (no login); translated transcripts (YouTube refuses them); search queries as input, SRT/VTT, chapters (not in this version).
- **Input:** `videos`, `channels` and/or `playlists` (links or IDs); `languages` in order (default en); optional `fallbackToAnyLanguage` and `allowAutoGenerated` (default on), `includeTimestamps` (default on), `channelContent`, `maxVideosPerSource` (0 = all), `includeVideosWithoutTranscript`, `onlyNew` + `stateName`, `maxConcurrency`.
- **Output:** one dataset row per transcript delivered (and, if asked, a free row per video without one), and one `SUMMARY` record with one item per input. Every field with its type is under *Output reference* below.
- **Charged events (pay per event):** `transcript`, one per transcript delivered (price in the Price section below); plus Apify's standard start event `apify-actor-start`.
- **Never charged:** videos without subtitles, private, deleted, age-restricted or members-only videos, videos that could not be read, repeats, videos already delivered in monitoring mode, the free rows, the SUMMARY record; a run that delivers no transcript costs nothing beyond `apify-actor-start`.
- **Limits:** stops at `maxVideosPerSource` or at your maximum charge per run (SUMMARY `stoppedBy`); after 20 failed videos in a row the run stops with the reason; monitoring remembers the last 100,000 videos per `stateName`.
- **Run it from:** Apify Console, the Apify API or an AI agent through the Apify MCP server (Actor `pampadata/youtube-transcripts-bulk`), with schedules and integrations.

#### Minimal input

A small input that works, taken from this Actor's own tests; every other field is optional:

```json
{
  "videos": [
    "dQw4w9WgXcQ"
  ],
  "languages": [
    "es",
    "en"
  ]
}
```

### Why this one

- **Whole channels, past 200.** The Actor reads a channel's Videos tab (and, if you ask, Shorts and Live) page by page until YouTube says there is nothing more. Test on 2026-10-13:

| Channel | Videos on the channel (yt-dlp count) | Listed by this Actor | Transcripts delivered |
|---|---|---|---|
| Veritasium (Videos tab) | 451 | **451** | **448** (2 age-restricted, 1 without subtitles) |
| Wendover Productions (Videos tab) | 288 | **288** | **287** (1 age-restricted) |

- **Playlists and video lists**, mixed with channels in one run. A video that shows up in two of your inputs is delivered and charged once.
- **Your language, or the next one.** List languages in order (`en`, `es`, `pt`…). The first one the video has is used; `es` also takes `es-419` and `es-ES`. If the video has none of them, you still get its own subtitles, marked `fallbackUsed: true` (turn that off and such videos are skipped, free).
- **Manual or auto-generated, always said.** Every row has `kind: "manual"` or `"auto-generated"`. Inside a language, subtitles written by a person come first. Turn off `allowAutoGenerated` to get only those.
- **Timestamps.** `segments: [{start, duration, text}]` in seconds, plus the full `text`.
- **A check per input** (SUMMARY record): videos listed, transcripts delivered, how many came from the fallback or were auto-generated, every video without a transcript **with the reason** (no subtitles, private, deleted, age-restricted, members-only, live not finished; the first 300 per input are listed by id, all are counted in `byStatus`), and `listComplete: true` only when the list was read to its end.
- **Only new videos, for monitoring.** Turn on `onlyNew` and the Actor remembers which transcripts it delivered (one memory per `stateName`, shared by all inputs, in a key-value store of your own account; the last 100,000 videos): a scheduled run delivers and charges only new ones, also when the same video comes through another channel, playlist or link. Videos that had no subtitles yet are tried again next time (YouTube adds automatic subtitles some hours after upload).
- **No YouTube API key, no login.** It reads the same public data the YouTube apps read.

### Input

| Field | What it does |
|---|---|
| `videos` | Video links (watch, youtu.be, shorts, live, embed) or 11-character ids. |
| `channels` | `@handle`, `youtube.com/@handle`, `/channel/UC…`, `/c/name`, `/user/name`. Read to the end. |
| `playlists` | `youtube.com/playlist?list=…` or the id (`PL…`). Read to the end. Mixes (`RD…`), Watch later and Liked videos are personal lists and are not supported. |
| `languages` | Codes in order of preference. Default `en`. |
| `fallbackToAnyLanguage` | On by default: no asked language → the video's own subtitles. |
| `allowAutoGenerated` | On by default. Off = only subtitles written by a person. |
| `includeTimestamps` | On by default (`segments`). Off = plain text only (smaller rows). |
| `channelContent` | `videos` (default), `shorts`, `streams` (past live streams). |
| `maxVideosPerSource` | 0 = all. Newest first on channels, list order on playlists. |
| `includeVideosWithoutTranscript` | Off by default. On = also a free row (with `status` and `reason`) for each video without a transcript. |
| `onlyNew`, `stateName` | Monitoring: skip videos whose transcript was delivered by earlier runs with the same state name. |
| `maxConcurrency` | Videos read at the same time, at most (default 4). The run slows down by itself when YouTube pushes back. |

### What you get for each video

`videoId`, `url`, `title`, `channelName`, `channelId`, `publishedAt` (YouTube's date, with its time zone), `durationSeconds`, `viewCount`, `language`, `languageName`, `kind`, `languageMatched` (the asked code it answered, or null), `fallbackUsed`, `availableLanguages`, `segmentCount`, `wordCount`, `text`, `segments`, `input`, `sourceType`.

#### Example

```json
{
  "videoId": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channelName": "Rick Astley",
  "publishedAt": "2009-10-24T23:57:33-07:00",
  "durationSeconds": 213,
  "language": "es-419",
  "kind": "manual",
  "languageMatched": "es",
  "fallbackUsed": false,
  "availableLanguages": ["de-DE", "en", "en (auto)", "es-419", "ja", "pt-BR"],
  "segments": [{"start": 18.64, "duration": 3.24, "text": "Conocemos bien el amor"}],
  "text": "Conocemos bien el amor Tú conoces las reglas, igual que yo …"
}
```

### Price

You pay only for transcripts delivered: **USD 1.50 per 1,000 transcripts** (USD 0.0015 each; one row is one video's transcript with timestamps and full text). No charge per run beyond Apify's standard start event: **a run that delivers no transcript is not charged for anything else**, and nothing is charged for videos without subtitles, private, deleted, age-restricted or members-only videos, videos that could not be read, repeats, videos already delivered in an earlier monitoring run, the free rows of `includeVideosWithoutTranscript`, or the SUMMARY record. Set a maximum charge per run in Apify and the Actor stops there (it does not even read videos it could not deliver).

### How long it takes

One video in about a second. 451 videos of one channel in under 2 minutes (test on 2026-10-13, 4 at a time).

### Good to know

- **Only public subtitles.** The Actor reads each video's public subtitle tracks and basic video details (title, channel, date, duration, views). It does **not** collect comments, viewers' data or anything behind a login. A transcript is what was said in the video, so it can name people: that is the published content of the video.
- **Auto-generated subtitles** are YouTube's speech recognition: words can be wrong and there is little punctuation. Check `kind`.
- **Translated transcripts are not offered**: YouTube refuses its machine-translation requests (measured).
- **Age-restricted, private and members-only videos** need a signed-in account; the Actor never signs in, so they are reported, not delivered.
- **When YouTube pushes back**, the run slows down and, on Apify, moves to residential IPs by itself (that traffic is included in the price). Videos that still cannot be read are reported as `failed` and not charged.
- Monitoring: one `stateName` per monitor, and don't run two runs with the same `stateName` at the same time.
- **Not affiliated with YouTube or Google.** "YouTube" names the public source of the data.

### Output reference

#### Dataset: one row per transcript

| Field | Type | What it is |
|---|---|---|
| `videoId` | string | 11-character video ID. |
| `url` | string | Watch link. |
| `title` | string | Video title. |
| `channelName` | string | Channel name. |
| `channelId` | string | Channel ID (UC…). |
| `publishedAt` | string or null | YouTube's publish date, with its time zone. |
| `durationSeconds` | integer | Duration in seconds. |
| `viewCount` | integer | Views when read. |
| `language` | string | Language code of the transcript (e.g. en, es-419). |
| `languageName` | string | Language name as YouTube gives it. |
| `kind` | string | manual (written by a person) or auto-generated. |
| `languageMatched` | string or null | The asked code it answered (null when the fallback was used). |
| `fallbackUsed` | boolean | true when none of your languages existed and the video's own subtitles were taken. |
| `availableLanguages` | array of string | Every subtitle track of the video (" (auto)" marks auto-generated). |
| `segmentCount` | integer | Number of segments. |
| `wordCount` | integer | Number of words. |
| `text` | string or null | The full transcript as plain text (null on free rows). |
| `segments` | array of object | With includeTimestamps: start and duration in seconds, text. |
| `input` | string | Your input line this video came from. |
| `sourceType` | string | video, channel or playlist. |
| `status` | string | Only on free rows (includeVideosWithoutTranscript): why there is no transcript, e.g. noTranscript, private, age, members, live, unavailable, failed. |
| `reason` | string or null | Only on free rows: YouTube's reason text. |

#### SUMMARY record (run's key-value store, never charged)

| Field | Type | What it is |
|---|---|---|
| `inputs` | array of object | One item per input line (fields below). |
| `transcriptsDelivered` | integer | Transcripts delivered (charged) in the run. |
| `freeRowsDelivered` | integer | Free rows for videos without a transcript. |
| `languages`, `fallbackToAnyLanguage`, `allowAutoGenerated`, `channelContent` | array, boolean, boolean, array | Settings used. |
| `onlyNew`, `stateName` | boolean, string or null | Monitoring settings. |
| `stoppedBecauseBlocked` | boolean | true when YouTube kept refusing and the run stopped. |
| `requests` | object | Request counters of the run (requests, retries, refusals or blocks, failures; whether the run moved to residential IPs). |

Each item of `inputs`:
| Field | Type | What it is |
|---|---|---|
| `input` | string | Your input line. |
| `type` | string | video, channel, playlist or invalid. |
| `listed` | integer | Videos listed for this input. |
| `transcripts` | integer | Transcripts delivered (charged). |
| `deliveredFree` | integer | Free rows delivered. |
| `autoGenerated`, `fallbackUsed` | integer | Transcripts that were auto-generated / came from the fallback. |
| `alreadyDelivered`, `seenInEarlierRuns` | integer | Repeats in the run; monitoring repeats (not charged). |
| `listPages` | integer | List pages read. |
| `byStatus` | object | Count per video status (ok, noTranscript, private, age, members, live, failed…). |
| `listComplete` | boolean | true only when the list was read to its end. |
| `videosWithoutTranscript` | array of object | videoId, status, reason (first 300). |
| `stoppedBy` | string or null | Why it stopped early (maxVideosPerSource, your maximum charge…). |
| `incompleteParts`, `warnings`, `errors` | array | What was not read, warnings, errors. |

### More Actors by this developer

- [Google Ads Transparency Scraper](https://apify.com/pampadata/google-ads-transparency-scraper)
- [SEEK Jobs Scraper (Seek, JobStreet, Jobsdb)](https://apify.com/pampadata/seek-jobs-scraper)
- [Career Site Jobs Scraper (Workday, Greenhouse, Lever and 6 more)](https://apify.com/pampadata/career-site-jobs-scraper)
- [AliExpress Search Scraper](https://apify.com/pampadata/aliexpress-search-scraper)
- [Google News Scraper](https://apify.com/pampadata/google-news-scraper)
- [Sports Odds vs Prediction Markets (Kalshi, Polymarket)](https://apify.com/pampadata/sports-odds-vs-prediction-markets)
- [Google Trends Scraper](https://apify.com/pampadata/google-trends-scraper)

***

### Versión en español

Transcripciones de **canales de YouTube completos** (sin tope de 200 videos: la lista del canal se lee hasta el final), **listas de reproducción** y listas de videos, en una sola corrida. Cada fila trae la transcripción **con marcas de tiempo** y como texto corrido, en **tu idioma o el siguiente disponible**, y dice si los subtítulos los **escribió una persona o son automáticos**. Pagás solo por transcripción entregada: **una corrida que no encuentra nada no cuesta nada aparte del evento de inicio de Apify, y un video sin subtítulos nunca se cobra.**

#### De un vistazo

- **Qué hace:** Transcripciones de canales completos de YouTube (sin tope de 200), listas y videos sueltos, con marcas de tiempo y texto corrido, en tu idioma o el siguiente, marcando manual o automático.
- **Sirve para:** el texto de los videos de un canal o lista para búsqueda, análisis, resúmenes o flujos de IA; monitorear canales.
- **No sirve para:** comentarios o datos de quienes miran; videos con restricción de edad, privados o de miembros (sin iniciar sesión); transcripciones traducidas; búsquedas como entrada, SRT/VTT, capítulos.
- **Entrada:** `videos`, `channels` y/o `playlists`; `languages` en orden (en por defecto); opcionales de respaldo, automáticos, marcas de tiempo, `channelContent`, `maxVideosPerSource`, `includeVideosWithoutTranscript`, `onlyNew` + `stateName`, `maxConcurrency`. Ejemplo mínimo en JSON: sección *Minimal input* de la parte en inglés.
- **Salida:** una fila por transcripción (y, si lo pedís, una fila gratis por video sin ella) y un registro `SUMMARY` con un ítem por entrada.
- **Eventos que se cobran:** `transcript`, una por transcripción entregada (precio en la sección Precio); más `apify-actor-start`.
- **Nunca se cobra:** videos sin subtítulos, privados, borrados, con restricción o de miembros, ilegibles, repetidos, ya entregados, las filas gratis, el SUMMARY; una corrida sin transcripciones no cuesta nada aparte de `apify-actor-start`.
- **Límites:** se detiene en `maxVideosPerSource` o en tu costo máximo por corrida (`stoppedBy`).

#### Por qué este

- **Canales completos, más allá de 200.** El Actor lee la pestaña Videos del canal (y, si pedís, Shorts y En vivo) página por página hasta que YouTube dice que no hay más. Prueba del 2026-10-13: Veritasium, 451 videos en el canal → **451 listados, 448 transcripciones** (2 con restricción de edad, 1 sin subtítulos); Wendover Productions, 288 → **288 listados, 287 transcripciones**.
- **Listas de reproducción y listas de videos**, mezcladas con canales en la misma corrida. Un video que aparece en dos de tus entradas se entrega y se cobra una vez.
- **Tu idioma, o el siguiente.** Poné idiomas en orden (`es`, `en`, `pt`…). Se usa el primero que tenga el video; `es` también toma `es-419` y `es-ES`. Si el video no tiene ninguno, igual recibís sus propios subtítulos, marcados `fallbackUsed: true` (si lo apagás, esos videos se saltean, gratis).
- **Manual o automático, siempre dicho.** Cada fila trae `kind: "manual"` o `"auto-generated"`. Dentro de un idioma, primero los escritos por una persona. Apagá `allowAutoGenerated` para recibir solo esos.
- **Marcas de tiempo:** `segments: [{start, duration, text}]` en segundos, más el `text` completo.
- **Control por entrada** (registro SUMMARY): videos listados, transcripciones entregadas, cuántas salieron del respaldo o fueron automáticas, cada video sin transcripción **con el motivo** (sin subtítulos, privado, borrado, restricción de edad, solo para miembros, en vivo sin terminar; los primeros 300 por entrada van con su id, todos se cuentan en `byStatus`), y `listComplete: true` solo cuando la lista se leyó hasta el final.
- **Solo videos nuevos, para monitoreo:** con `onlyNew`, el Actor recuerda qué transcripciones entregó (una memoria por `stateName`, compartida por todas las entradas, en un almacén de tu propia cuenta; los últimos 100.000 videos) y cada corrida programada entrega y cobra solo las nuevas, también si el mismo video llega por otro canal, lista o link. Los videos que todavía no tenían subtítulos se vuelven a probar (YouTube agrega los automáticos unas horas después de subir el video).
- **Sin clave de la API de YouTube y sin iniciar sesión.**

#### Precio

Pagás solo las transcripciones entregadas: **USD 1,50 cada 1.000 transcripciones** (USD 0,0015 cada una; una fila es la transcripción de un video con marcas de tiempo y texto completo). No hay cargo por corrida aparte del evento de inicio estándar de Apify: **una corrida que no entrega ninguna transcripción no se cobra por nada más**, y no se cobran los videos sin subtítulos, privados, borrados, con restricción de edad o solo para miembros, los que no se pudieron leer, los repetidos, los ya entregados en una corrida anterior de monitoreo, las filas gratis de `includeVideosWithoutTranscript` ni el registro SUMMARY. Poné un cargo máximo por corrida en Apify y el Actor se detiene ahí (ni siquiera lee videos que no podría entregar).

#### Para saber

- **Solo subtítulos públicos.** El Actor lee los subtítulos públicos de cada video y sus datos básicos (título, canal, fecha, duración, vistas). **No** junta comentarios, datos de quienes miran ni nada que requiera iniciar sesión. Una transcripción es lo que se dijo en el video y puede nombrar personas: es el contenido publicado del video.
- **Los subtítulos automáticos** son el reconocimiento de voz de YouTube: puede haber palabras mal y poca puntuación. Mirá `kind`.
- **No se ofrecen transcripciones traducidas:** YouTube rechaza sus pedidos de traducción automática (medido).
- **Los videos con restricción de edad, privados o solo para miembros** piden una cuenta; el Actor nunca inicia sesión, así que se informan y no se entregan.
- **Cuando YouTube frena**, la corrida baja el ritmo y, en Apify, pasa sola a IPs residenciales (ese tráfico está incluido en el precio). Los videos que igual no se pueden leer se informan como `failed` y no se cobran.
- Monitoreo: un `stateName` por monitor, y no corras dos corridas con el mismo `stateName` a la vez.
- **Sin relación con YouTube ni con Google.** "YouTube" nombra la fuente pública de los datos.

# Actor input Schema

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

One per line: a video link (youtube.com/watch?v=…, youtu.be/…, /shorts/…, /live/…) or an 11-character video id.

## `channels` (type: `array`):

One per line: @handle, youtube.com/@handle, /channel/UC…, /c/name or /user/name. The channel's list is read to the end, however many videos it has. Use 'Maximum transcripts per channel or playlist' for a quick test.

## `playlists` (type: `array`):

One per line: a youtube.com/playlist?list=… link or a playlist id (PL…). Read to the end. Mixes (RD…), Watch later and Liked videos are personal lists and are not supported.

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

Language codes: en, es, pt, de, fr, ja… The first one the video has is used ('es' also takes es-419 or es-ES). Inside a language, subtitles written by a person come before auto-generated ones.

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

On: a video without your languages still gives its transcript in the language it has (marked fallbackUsed: true). Off: such a video gives no transcript and is not charged.

## `allowAutoGenerated` (type: `boolean`):

YouTube's automatic subtitles (speech recognition). Every row says kind: manual or auto-generated. Off: only subtitles written by a person; videos with only automatic ones give no transcript and are not charged.

## `includeTimestamps` (type: `boolean`):

Adds segments: \[{start, duration, text}] in seconds. The full plain text is always in 'text'.

## `channelContent` (type: `array`):

The channel tabs to read, each to the end.

## `maxVideosPerSource` (type: `integer`):

0 = all. Newest first on channels, list order on playlists. You pay per transcript, so set a limit for quick tests.

## `includeVideosWithoutTranscript` (type: `boolean`):

Off: videos without subtitles, private, deleted or age-restricted are listed with the reason in the SUMMARY record only. On: they also get a dataset row with status and reason. Those rows are never charged.

## `onlyNew` (type: `boolean`):

For monitoring channels or playlists: the run remembers which transcripts it delivered (one memory per state name, shared by all inputs, in a key-value store of your account; the last 100,000) and skips them next time. Videos that had no transcript yet are tried again (YouTube adds automatic subtitles some hours after upload).

## `stateName` (type: `string`):

Separate memories for separate monitors: runs with the same name share what was already delivered.

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

The run slows down by itself when YouTube refuses requests; this is the ceiling.

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

Leave off: the run uses its own IP and, when YouTube refuses it, moves to residential IPs by itself (that traffic is included in the price). Set a proxy here only to force your own.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "languages": [
    "en"
  ],
  "fallbackToAnyLanguage": true,
  "allowAutoGenerated": true,
  "includeTimestamps": true,
  "channelContent": [
    "videos"
  ],
  "maxVideosPerSource": 0,
  "includeVideosWithoutTranscript": false,
  "onlyNew": false,
  "stateName": "default",
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset items: one row per transcript (videoId, url, title, channelName, channelId, publishedAt, durationSeconds, viewCount, language, kind manual/auto-generated, languageMatched, fallbackUsed, availableLanguages, text, segments with start/duration, input, sourceType). Charged per row: event `transcript`. With includeVideosWithoutTranscript, free rows with status and reason.

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

Key-value record SUMMARY: per input, videos listed, transcripts delivered, auto-generated and fallback counts, videos without a transcript with their reason (first 300 per input; all counted in byStatus), listComplete, stoppedBy; run totals. Not charged.

# 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=dQw4w9WgXcQ"
    ],
    "languages": [
        "en"
    ],
    "maxVideosPerSource": 0,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("pampadata/youtube-transcripts-bulk").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=dQw4w9WgXcQ"],
    "languages": ["en"],
    "maxVideosPerSource": 0,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("pampadata/youtube-transcripts-bulk").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=dQw4w9WgXcQ"
  ],
  "languages": [
    "en"
  ],
  "maxVideosPerSource": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call pampadata/youtube-transcripts-bulk --silent --output-dataset

```

## MCP server setup

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

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/JQ8rzUClSPssUlXvb/builds/1gmA6vWjfgDh7ZOr0/openapi.json
