# YouTube Caption & Whisper AI Transcript Extractor (`nimbryxo-studio/youtube-caption-and-whisper-ai-transcript`) Actor

Get timestamped transcripts from YouTube videos in your preferred language, with optional AI transcription for videos that have no captions at all. Returns full text, timed segments, and core video metadata.

- **URL**: https://apify.com/nimbryxo-studio/youtube-caption-and-whisper-ai-transcript.md
- **Developed by:** [Nimbryxo-studio](https://apify.com/nimbryxo-studio) (community)
- **Categories:** AI, Automation, Videos
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Caption & Whisper AI Transcript Extractor

Get the transcript of any public YouTube video — timestamped segments, a full plain-text version, language info, and core video details — ready for AI pipelines, content repurposing, translation, and research.

When a video has no captions at all (the uploader disabled them, or it's music-only with no on-screen text), optional AI transcription can transcribe the audio directly so you still get a usable transcript.

### What this actor does

- Returns every transcript segment with its start time, duration, and text, plus the full transcript as one string
- Lets you request a specific caption language; YouTube's own translation is used when your language isn't natively available
- With `useWhisper` on (the default), falls through to AI-generated transcription when YouTube has no captions at all, so you still get usable text
- Processes multiple videos in one run, each pushed as its own record
- Fields that don't apply to a given video (e.g. no `like_count` when YouTube didn't expose one) are left out of that record

### Output per video

- `video_id`, `title`, `channel_name`, `channel_id`
- `duration_seconds`, `views`, `like_count`, `published_date`, `thumbnail`
- `category`, `keywords`, `description`
- `is_live_content`, `is_upcoming`, `is_family_safe`
- `transcript_language`, `transcript_language_name`, `requested_language`, `language_matched`
- `is_auto_generated` — `true` for YouTube's auto-caption, `false` for manually uploaded captions, translated captions, or AI-generated output
- `was_translated` — `true` only when YouTube translated an available caption track to your requested language
- `transcript_source` — which path produced the transcript: `library`, `caption_url`, `android_player`, `innertube`, `playwright_dom`, or `whisper`
- `language_probability` — language-detection confidence, only set when `transcript_source` is `whisper`
- `available_languages` — every transcript language YouTube offers for the video
- `segments` — timestamped entries, each with `start`, `dur` (seconds, as strings with three decimals) and `text`; left out when `outputFormat` is `text_only`
- `full_text` — the whole transcript as one string; left out when `outputFormat` is `segments_only`
- `segment_count`, `transcript_available`
- `success` — `true` when a transcript was extracted
- `error` — reason text when `success` is `false`
- `inputUrl`, `scrapedAt`

A video that fails gets a row with `success: false`, an `error` message, `inputUrl`, `scrapedAt` and whatever video details were found (an unrecognisable URL gets only the first four). If the run gets close to its timeout, videos not yet started are written as `success: false` rows with the error "Run time budget reached before processing", so every input still has a row. An input that fails validation (for example an empty `videoUrls` list) produces a single `success: false` row explaining why.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `videoUrls` | Array | – | YouTube watch URLs, `youtu.be` short links, Shorts URLs, embed URLs, or plain 11-char video IDs. Required. |
| `language` | String | `""` | Preferred language code (`en`, `es`, `fr`, `de`, `ja`, `ko`, …). Empty = best available. |
| `includeAutoGenerated` | Boolean | `true` | Include YouTube auto-captions when manual ones aren't available. |
| `useWhisper` | Boolean | `true` | Transcribe the video's audio with AI when YouTube has no transcript at all. Adds ~30-180 s per video. This output is derived speech-to-text, not a YouTube caption. |
| `whisperModel` | Enum | `base` | `tiny`, `base`, `small`, `medium`, or `large-v3-turbo` |
| `proxyCountry` | Enum | `US` | One of the 31 schema-supported country/region codes |
| `outputFormat` | Enum | `full` | `full`, `text_only`, or `segments_only` |

#### Supported URL formats

- `https://www.youtube.com/watch?v=dQw4w9WgXcQ`
- `https://youtu.be/dQw4w9WgXcQ`
- `https://www.youtube.com/shorts/VIDEO_ID`
- `https://www.youtube.com/embed/VIDEO_ID`
- Plain 11-char ID: `dQw4w9WgXcQ`

#### Example input — multiple videos, English preferred

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/9bZkp7q19f0",
    "https://www.youtube.com/shorts/abc123XYZ45"
  ],
  "language": "en",
  "includeAutoGenerated": true
}
```

#### Example input — AI transcription for videos with no captions

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=XqZsoesa55w"],
  "useWhisper": true,
  "whisperModel": "small"
}
```

### Examples

```json
{
  "video_id": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channel_name": "Rick Astley",
  "channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
  "duration_seconds": 213,
  "views": 1769190465,
  "published_date": "2009-10-24",
  "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
  "transcript_language": "en",
  "transcript_language_name": "English",
  "is_auto_generated": false,
  "transcript_source": "caption_url",
  "available_languages": [
    { "code": "en", "name": "English", "is_auto_generated": false },
    { "code": "es-419", "name": "Spanish (Latin America)", "is_auto_generated": false }
  ],
  "segments": [
    { "start": "1.360", "dur": "1.680", "text": "[♪♪♪]" },
    { "start": "18.640", "dur": "3.240", "text": "We're no strangers to love" }
  ],
  "segment_count": 61,
  "full_text": "[♪♪♪] We're no strangers to love You know the rules and so do I ...",
  "success": true,
  "inputUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "scrapedAt": "2026-05-05T13:42:18Z"
}
```

#### Example: English transcript

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "language": "en",
  "outputFormat": "full"
}
```

#### Example: translated transcript

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "language": "es"
}
```

#### Example: AI transcription for videos without captions

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
  "useWhisper": true,
  "whisperModel": "base"
}
```

### Use cases

- **AI training data** — Build text corpora from YouTube content for LLM fine-tuning or RAG pipelines.
- **Content repurposing** — Turn long videos into blog posts, summaries, or social copy.
- **Research and analysis** — Pull spoken content from lectures, interviews, podcasts, and documentaries.
- **Subtitles and accessibility** — Retrieve captions for translation or accessibility workflows.
- **SEO and keyword research** — Analyse spoken keywords and topics across YouTube content.
- **Competitive intelligence** — Monitor what competitors say in their videos.
- **Education** — Extract transcripts from online courses for indexing or study notes.
- **Sentiment analysis** — Run sentiment or topic models against transcripts at scale.

### FAQ

**Which videos can I scrape?**
Any public YouTube video that has manually created or auto-generated captions, plus — with `useWhisper` on — public videos without captions whose audio can be downloaded. Private videos, deleted videos, and members-only videos cannot be scraped — those return `success=false` with an error message.

**What if a video has no captions at all?**
Set `useWhisper: true` to transcribe the audio with AI. For clear speech, `whisperModel=base` is the sweet spot. For music, noisy audio, or short clips, use `whisperModel=small` for noticeably better accuracy.

**What if my requested language isn't available?**
An exact match (`en`) is tried first, then regional variants (`en` matches `en-GB`, `en-US`), then the best available transcript. The `available_languages` field always lists everything on offer for that video.

**What's the difference between `transcript_source` values?**

- `caption_url` / `android_player` — pulled directly from YouTube's own published caption tracks (fastest, most reliable, real human or YouTube auto-captions).
- `innertube` — pulled from an alternate YouTube data endpoint when the primary path didn't return captions.
- `playwright_dom` — extracted straight from the video page's own transcript panel as a last resort.
- `whisper` — generated with AI from the video's audio when YouTube has no captions at all.

**How accurate are auto-generated captions vs Whisper?**
YouTube auto-captions are generally accurate for clear English speech. Whisper `base` is comparable for clean audio, and Whisper `small` typically beats YouTube on accents, multiple speakers, and noisy audio. Both struggle on music with non-vocal singing.

**The Whisper output looks like garbage / repetitive text.**
Whisper-tiny on music or near-silent clips can hallucinate repetitive phrases. The actor automatically detects this (low language-detection confidence + identical segment text) and returns `success=false` with an actionable error pointing you at a larger model. Re-run with `whisperModel=small` for music videos.

**Can I scrape multiple videos in one run?**
Yes — pass an array of URLs. Videos are processed a couple at a time and each is pushed as its own dataset row, so rows may not appear in the same order as your input; use `inputUrl` or `video_id` to match them up.

**How current is the data?**
Live — every run hits YouTube at request time. Schedule the actor for daily / hourly refreshes.

**Is this affiliated with YouTube?**
No. This is an independent, third-party actor that reads YouTube's publicly available caption data; it is not affiliated with, endorsed by, or operated by YouTube or Google.

### Limitations

- Private, members-only, age-restricted, and deleted videos cannot be scraped.
- AI transcription adds roughly 30-180 s per video depending on length and model size.
- AI transcription accuracy on heavy music or pure-instrumental audio is fundamentally limited regardless of model size.
- YouTube can change how it serves captions at any time; a transient issue on YouTube's side may still cause `success=false` for individual videos.

# Actor input Schema

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

YouTube video URLs, short links (youtu.be), shorts URLs, or plain video IDs.

## `language` (type: `string`):

Caption language to fetch. Leave Auto-detect to use the video's original language.

## `includeAutoGenerated` (type: `boolean`):

Whether to include auto-generated captions when manual captions are not available.

## `useWhisper` (type: `boolean`):

When YouTube has no transcript (disabled captions, music-only, or blocked), download the audio and transcribe with Whisper AI (faster-whisper, CPU). Adds ~30-180 s per video. Enabled by default to guarantee transcript output even when YouTube captions are unavailable.

## `whisperModel` (type: `string`):

Whisper model size to use when `useWhisper` is enabled. Larger = more accurate but slower and more RAM. 'base' is balanced.

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

Country/region for the proxy IP. Useful if transcripts are geo-blocked in the default US region.

## `outputFormat` (type: `string`):

Controls how transcript data is included in the output. 'full' = all fields including segments array. 'text_only' = only full_text (no segments array, smaller output). 'segments_only' = only the segments array (no full_text).

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "language": "",
  "includeAutoGenerated": true,
  "useWhisper": true,
  "whisperModel": "tiny",
  "proxyCountry": "US",
  "outputFormat": "full"
}
```

# Actor output Schema

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

Dataset containing all scraped transcripts with timed segments and video metadata.

# 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=jNQXAC9IVRw"
    ],
    "includeAutoGenerated": true,
    "useWhisper": true,
    "whisperModel": "tiny"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nimbryxo-studio/youtube-caption-and-whisper-ai-transcript").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=jNQXAC9IVRw"],
    "includeAutoGenerated": True,
    "useWhisper": True,
    "whisperModel": "tiny",
}

# Run the Actor and wait for it to finish
run = client.actor("nimbryxo-studio/youtube-caption-and-whisper-ai-transcript").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=jNQXAC9IVRw"
  ],
  "includeAutoGenerated": true,
  "useWhisper": true,
  "whisperModel": "tiny"
}' |
apify call nimbryxo-studio/youtube-caption-and-whisper-ai-transcript --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nimbryxo-studio/youtube-caption-and-whisper-ai-transcript"
        }
    }
}
```

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/yNFXZ2tJKz5wBMxDw/builds/gcaMU2mlIU9x6pvl7/openapi.json
