# YouTube Captions (`scrapewise/youtube-captions`) Actor

Extract YouTube captions by type (manual or auto-generated) and language, and list every caption track a video has. Text, timestamps, SRT or VTT, with title, views and publish date. Videos without captions are free. Pay per video.

- **URL**: https://apify.com/scrapewise/youtube-captions.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Videos, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 captions delivereds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## YouTube Captions

Extract YouTube captions by **type** (manual or auto-generated) and language, and see **every caption track** each video has. Get the caption text, timestamps, SRT or VTT, with the video's title, views and publish date.

### What you get

- **Manual vs auto-generated, your call.** `captionType: "manual"` returns human-made captions only, `"auto"` only YouTube's automatic ones, `"any"` the best available.
- **The full list of caption tracks** in `captionTracks`: language code, name, whether it is auto-generated and whether YouTube can translate it. Know what exists before you pick.
- **Language preference** in order, e.g. `["pt-BR", "pt", "en"]`.
- **Timestamps** in `segments` (text, start, duration), plus optional SRT and VTT.
- **Videos without captions never fail the run.** They come back with an `errorCode` and are **not charged**. A video without captions of the requested type still lists the tracks it does have.
- **Video details included:** `title`, `channel`, `publishedAt`, `viewCount`, `lengthSeconds`.

### Use cases

- Check which videos have human-made captions for accessibility audits or caption QA.
- Build training or evaluation data from manual captions only, skipping auto-generated noise.
- Find which languages a set of videos is captioned in before localizing.

### Input

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=iG9CE55wbtY", "dQw4w9WgXcQ"],
  "captionType": "manual",
  "languages": ["en", "es"],
  "includeSegments": true,
  "maxItems": 50
}
```

| Field | What it does |
|---|---|
| `videoUrls` | Video URLs or IDs. Playlist, channel and search URLs also work. |
| `captionType` | `any`, `manual` or `auto`. |
| `languages` | Caption languages in order of preference. |
| `includeSegments` | Timestamped caption lines (default on). |
| `subtitleFormats`, `translateTo` | Advanced: SRT/VTT fields and YouTube translation. |
| `maxVideosPerSource`, `publishedAfter`, `includeShorts`, `onlyNewVideos` | Advanced: for playlists, channels and searches. |
| `maxItems` | Hard limit for the whole run (default 50). |

### Output

One item per video:

```json
{
  "videoId": "iG9CE55wbtY",
  "url": "https://www.youtube.com/watch?v=iG9CE55wbtY",
  "title": "Do schools kill creativity? | Sir Ken Robinson | TED",
  "channel": "TED",
  "publishedAt": "2007-01-07T00:00:00+00:00",
  "viewCount": 26000000,
  "language": "en",
  "isAutoGenerated": false,
  "captionTracks": [
    { "languageCode": "ar", "name": "Arabic", "isAutoGenerated": false, "isTranslatable": true },
    { "languageCode": "en", "name": "English", "isAutoGenerated": false, "isTranslatable": true },
    { "languageCode": "en", "name": "English (auto-generated)", "isAutoGenerated": true, "isTranslatable": true }
  ],
  "text": "Good morning. How are you? ...",
  "segments": [{ "text": "Good morning. How are you?", "start": 15.2, "duration": 2.4 }],
  "errorCode": null,
  "scrapedAt": "2026-09-13T01:30:00+00:00"
}
```

Items that could not be delivered have `error` and `errorCode` filled in and are not charged:

| errorCode | Meaning |
|---|---|
| `NO_CAPTIONS` | The video has no captions at all |
| `NO_CAPTIONS_IN_LANGUAGE` | No captions of the requested type (see `captionTracks` for what exists) |
| `VIDEO_UNAVAILABLE` / `VIDEO_UNPLAYABLE` | Private, removed or region-locked video |
| `AGE_RESTRICTED` | Age restricted video |
| `LIVE_NOT_ENDED` | Live stream still running or upcoming |
| `BLOCKED` | YouTube blocked every attempt; try again |

### Pricing

**From US$ 3.50 per 1,000 videos with captions delivered, no monthly fee.** US$ 5.00 on the Free plan, lower on paid Apify plans:

| Apify plan | Per 1,000 videos with captions |
|---|---|
| Free | US$ 5.00 |
| Starter (Bronze) | US$ 4.50 |
| Scale (Silver) | US$ 4.00 |
| Business (Gold) and above | US$ 3.50 |

The track list is included. Videos without captions of the requested type, unavailable or blocked are free.

### How to use

- **Console:** paste the URLs, choose the caption type, click Start, export JSON, CSV or Excel.
- **API:** `POST https://api.apify.com/v2/acts/scrapewise~youtube-captions/run-sync-get-dataset-items?token=YOUR_TOKEN` with the input as the body.
- **Integrations:** n8n, Make, Zapier, Google Sheets and MCP clients through the Apify integrations.

### FAQ

**How do I know if a caption is auto-generated?**
`isAutoGenerated` on the item says it for the delivered caption, and each entry of `captionTracks` says it for every track.

**Can I get all languages of a video at once?**
One charge delivers one caption text, and `captionTracks` lists every language available. Run again with another `languages` value to get another language's text.

**Why did a video come back with NO\_CAPTIONS\_IN\_LANGUAGE?**
It has no captions of the requested `captionType`. For example, with `manual` a video with only auto-generated captions is skipped for free.

**Does it transcribe videos without captions?**
No. It reads the captions YouTube already has.

### Limitations

- Only videos with captions can be delivered.
- Age-restricted videos and running live streams are not supported.
- `captionTracks` can be empty when YouTube hides the track list from both app clients and the caption is recovered by a fallback method.
- YouTube blocks most datacenter IPs, so residential proxy is the default. Keep it on.
- Something broke? Open an issue on the Actor page. Issues are answered within 12 hours.

This Actor collects only public data and respects the site's terms.

### Changelog

- **2026-09-14:** lower price, from US$ 3.50 per 1,000 on paid plans (US$ 5.00 on Free).
- **2026-09-13, 0.1:** first release. Caption type filter, full caption track list, language preference, timestamps, SRT/VTT, video details.

Keywords: youtube captions, youtube captions downloader, youtube closed captions, youtube caption tracks, auto-generated captions.

# Actor input Schema

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

YouTube video URLs (watch, youtu.be, shorts, embed, live) or 11-character IDs. Playlist, channel and search URLs also work: their videos are expanded, limited by the advanced setting 'Max videos per channel, playlist or search'.

## `captionType` (type: `string`):

Which captions to use. Videos without the requested type come back with errorCode NO\_CAPTIONS\_IN\_LANGUAGE and are not charged. Every item also lists all caption tracks of the video in 'captionTracks'.

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

Caption languages in order of preference (e.g. en, es, pt-BR). If none is available, the first manual caption is used, then the auto-generated one.

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

Adds a 'segments' array with text, start and duration (seconds) for each caption line.

## `subtitleFormats` (type: `array`):

Adds ready-to-use 'srt' and/or 'vtt' fields with the full caption file. Same price.

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

Language code to translate with YouTube's own translation (e.g. es, pt). YouTube refuses most of these requests; when it does, the original language is delivered and the reason is recorded in translationError.

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

For playlist, channel and search URLs: how many videos to take from each one.

## `publishedAfter` (type: `string`):

Skip videos published before this date (YYYY-MM-DD). Skipped videos produce no item and are not charged.

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

Include Shorts when listing a channel or a search. Off: regular videos and past live streams only.

## `onlyNewVideos` (type: `boolean`):

Remembers which videos of each channel, playlist or search already got delivered (in a named key-value store in your account, 'youtube-captions-only-new-videos') and skips them on the next runs. Ideal for a daily or weekly schedule. Videos without captions are tried again next time, free.

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

Hard limit for the whole run, across all inputs. Protects your budget.

## `tryDatacenterFirst` (type: `boolean`):

Each video is tried twice through datacenter proxy before falling back to the proxy below. Keeps runs fast and cheap.

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

YouTube blocks most datacenter IPs; residential proxy is the default and recommended.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=iG9CE55wbtY"
  ],
  "captionType": "any",
  "languages": [
    "en",
    "pt",
    "pt-BR",
    "es"
  ],
  "includeSegments": true,
  "subtitleFormats": [],
  "maxVideosPerSource": 10,
  "includeShorts": false,
  "onlyNewVideos": false,
  "maxItems": 50,
  "tryDatacenterFirst": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

No description

## `resultsCsv` (type: `string`):

No description

# 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=iG9CE55wbtY"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/youtube-captions").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=iG9CE55wbtY"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/youtube-captions").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=iG9CE55wbtY"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scrapewise/youtube-captions --silent --output-dataset

```

## MCP server setup

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

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/etghHrzHxlh8omhXf/builds/bRTZ2fZqIRGBZPCO8/openapi.json
