# YouTube Transcriber (`prodiger/youtube-transcriber`) Actor

Transcribe YouTube videos. Captions when available, OpenAI Whisper fallback (BYOK) for the rest. No YouTube account needed.

- **URL**: https://apify.com/prodiger/youtube-transcriber.md
- **Developed by:** [Arnas](https://apify.com/prodiger) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 caption transcripts

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Transcriber

Transcribe YouTube videos via captions when available, OpenAI Whisper API as fallback. **You bring your own OpenAI key**, you pay OpenAI directly for Whisper compute, the actor only charges for the transcript event itself. Single video URLs only in v1.

### What does YouTube Transcriber do?

YouTube Transcriber extracts the spoken content of a YouTube video as text. When the video has captions in your requested language, it grabs them directly (cheap and fast). When it doesn't, it downloads the smallest available audio format and sends it to OpenAI's Whisper API for transcription using your own OpenAI key. Output is plain text or structured JSON with timestamps. No YouTube account needed.

Built on `yt-dlp` (the most reliable YouTube extraction tool in 2026) plus `ffmpeg`, with the actor wrapping subprocess calls in a strict SSRF / shell-injection defense.

### Why use YouTube Transcriber?

- **Cheapest captions price on Apify Store** — $0.0005 per transcript on the captions path, matching the captions-only price leader
- **BYOK Whisper at zero markup** — when Whisper fallback fires you pay OpenAI directly (~$0.006/min). The actor charges $0.05 for the path (vs codepoetry's bundled $0.012/min × N min, ~5-6× cheaper for typical video lengths)
- **Predictable cost ceiling** — `maxWhisperMinutesPerRun` caps your OpenAI bill per run
- **Audio always fits Whisper's limit** — yt-dlp + ffmpeg picks smallest-format audio under 24 MB; configurable `maxDurationMinutes` (default 18)
- **In-product visibility** — every video produces a record (success or skip with reason), so you can see why something was skipped without scrolling logs
- **No silent leaks** — your OpenAI key is `isSecret: true` in the input form, never logged, sanitized from any error message before output

### Who is this for?

- **Researchers** — pull transcripts of academic talks, interviews, podcasts at scale
- **AI/ML engineers** — feed real human speech into pipelines, fine-tune models on real conversations
- **Journalists** — transcribe source video evidence quickly
- **Content marketers** — repurpose video content as text for SEO
- **Power users with an OpenAI account** — if you already have an OpenAI key, this actor is the cheapest way to get Whisper-quality transcripts for arbitrary YouTube videos

### How to use YouTube Transcriber

1. Open the actor input page
2. Paste YouTube video URLs into **Video URLs** (one per line). Bare 11-char video IDs also work.
3. Set **Preferred caption language** (default `en`)
4. Choose **Transcript method**: `auto` (captions → Whisper), `captions` (captions only, skip if missing), or `whisper` (Whisper only, ignore CC)
5. (Optional) Paste your **OpenAI API key** — only needed when a video lacks captions in your preferred language and you want Whisper to fill the gap. Captions-only workflows work without a key.
6. Pick **Output format**: `text` or `json`
7. Click **Start**
8. Download results from the Dataset tab as JSON, CSV, Excel, etc.

#### Example input

```json
{
    "videoUrls": [
        "https://www.youtube.com/watch?v=jNQXAC9IVRw",
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "preferredLanguage": "en",
    "transcriptMethod": "auto",
    "openaiApiKey": "sk-YOUR_KEY_HERE",
    "outputFormat": "text",
    "includeTimestamps": false,
    "maxDurationMinutes": 18,
    "maxWhisperMinutesPerRun": 60
}
````

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `videoUrls` | string\[] | — (required) | YouTube URLs (any standard format) or bare 11-char video IDs |
| `preferredLanguage` | string | `"en"` | BCP-47 code. Falls through to Whisper if not available. |
| `transcriptMethod` | enum | `"auto"` | `auto`, `captions`, or `whisper` |
| `openaiApiKey` | secret string | — (optional) | Your OpenAI API key. Required only when `transcriptMethod=whisper`. In `auto` mode, missing key means videos without captions are skipped (with reason `no-openai-key-no-fallback`) instead of failing the run. |
| `whisperModel` | enum | `"whisper-1"` | Only `whisper-1` supports `verbose_json` segment timestamps |
| `outputFormat` | enum | `"text"` | `text` or `json` |
| `includeTimestamps` | boolean | `false` | When `text`, prefix each segment with `[HH:MM:SS]` |
| `maxDurationMinutes` | integer | `18` | Skip videos longer than this. Default keeps audio under Whisper's 25 MB limit. |
| `maxWhisperMinutesPerRun` | integer | `60` | Bounds your OpenAI bill per run. `0` = unlimited. |
| `proxyConfiguration` | object | `RESIDENTIAL` | YouTube blocks datacenter IPs in 2026; RESIDENTIAL recommended |

### Output examples

#### Text format (success)

```json
{
    "videoId": "jNQXAC9IVRw",
    "videoUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
    "title": "Me at the zoo",
    "channelTitle": "jawed",
    "publishedAt": "2005-04-23T00:00:00.000Z",
    "durationSeconds": 19,
    "language": "en",
    "transcriptMethod": "captions",
    "outputFormat": "text",
    "transcript": "All right, so here we are, in front of the elephants, the cool thing about these guys is that they have really, really, really long trunks, and that's cool. And that's pretty much all there is to say.",
    "skipReason": null,
    "scrapedAt": "2026-04-19T20:35:00.000Z"
}
```

#### JSON format (success, with segment timestamps)

```json
{
    "videoId": "jNQXAC9IVRw",
    "videoUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
    "transcriptMethod": "captions",
    "outputFormat": "json",
    "transcript": [
        { "start": 0.36, "end": 4.32, "text": "All right, so here we are, in front of the elephants" },
        { "start": 4.32, "end": 8.5, "text": "the cool thing about these guys is that they have really" },
        { "start": 8.5, "end": 14.2, "text": "really really long trunks and that's cool" }
    ],
    "skipReason": null
}
```

#### Skip record (visibility into why a video wasn't transcribed)

```json
{
    "videoId": "OPf0YbXqDm0",
    "title": "Mark Ronson - Uptown Funk",
    "transcript": [],
    "skipReason": "no-captions",
    "outputFormat": "json",
    "transcriptMethod": "captions",
    "language": ""
}
```

Skip reasons you may see: `video-unavailable`, `over-duration-cap`, `live-stream`, `no-captions`, `no-openai-key-no-fallback`, `whisper-budget-exceeded`, `audio-download-failed`, `audio-exceeds-whisper-limit`, `whisper-api-error:401-invalid-key`, `whisper-api-error:402-insufficient-quota`, `whisper-api-error:429-rate-limit`, `whisper-api-error:5xx`, `whisper-api-error:network`.

### Pricing

This actor uses **pay-per-event** pricing — you pay only for what runs.

| Event | Price |
|-------|-------|
| `apify-actor-start` (run start, first 5s of compute included) | $0.003 |
| `transcript-captions` (one charge per captioned video transcribed) | $0.0005 |
| `transcript-whisper` (one charge per video routed to Whisper fallback) | $0.05 |

**The Whisper-path price covers our proxy bandwidth + audio download + Apify compute.** You additionally pay OpenAI ~$0.006/min for the actual Whisper API call (billed to your OpenAI account, not us).

#### Real-world examples

| Run | Apify side | Your OpenAI side | Total |
|-----|-----------|-----------------|-------|
| 1 captioned video | $0.003 + $0.0005 = **$0.0035** | $0 | **$0.0035** |
| 1 video, no captions, 5 min | $0.003 + $0.05 = $0.053 | 5 × $0.006 = $0.030 | **$0.083** |
| 1 video, no captions, 18 min (default cap) | $0.003 + $0.05 = $0.053 | 18 × $0.006 = $0.108 | **$0.161** |
| 10 captioned videos | $0.003 + 10 × $0.0005 = **$0.008** | $0 | **$0.008** |
| 10 videos, all need Whisper, avg 10 min | $0.003 + 10 × $0.05 = $0.503 | 100 × $0.006 = $0.600 | **$1.103** |

### How to scrape YouTube transcripts at scale

1. Set `transcriptMethod=captions` for the cheapest path — most popular videos have captions
2. For videos without captions, set `transcriptMethod=auto` with a real OpenAI key
3. Use `maxWhisperMinutesPerRun` to cap your OpenAI exposure per run (default 60 min = ~$0.36)
4. Schedule recurring runs via Apify scheduler for monitoring channels / playlists (process URLs in batches)
5. Pipe results to Google Sheets, BigQuery, Slack via Apify integrations

### Anti-bot resilience

- **yt-dlp 2026.03.17** pinned in the Docker image. The 2026 YouTube anti-bot environment (PoToken, SABR signature ciphers) is handled by yt-dlp's mature extractor stack — validated at 87% audio-download success rate against a representative video sample on RESIDENTIAL proxy with no PoToken plugin
- **RESIDENTIAL proxy default** — YouTube reliably blocks datacenter IPs in 2026
- **Real-Chrome User-Agent** sent on subprocess calls
- **Per-run summary log** lets you detect when audio-download success rate degrades

### Security and credential handling

- `openaiApiKey` is `isSecret: true` — masked in the Console input form and at rest
- Key is sent only to `api.openai.com` over HTTPS
- Errors from OpenAI are sanitized: `sk-*` patterns are masked before any log line, dataset record, or thrown error
- Audio files are written only to OS temp dir (never to the actor's Apify storage), deleted immediately after the Whisper call (try/finally), and best-effort cleaned on actor abort

### API usage

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('YOUR_USERNAME/youtube-transcriber').call({
    videoUrls: ['https://www.youtube.com/watch?v=jNQXAC9IVRw'],
    openaiApiKey: 'sk-YOUR_OPENAI_KEY',
    transcriptMethod: 'auto',
    outputFormat: 'text',
});

const { items } = await client.dataset(run.namedDatasetIds.transcripts).listItems();
console.log(items);
```

### FAQ

**Why do I need an OpenAI key?** Whisper transcription quality is best in class and we don't bundle the cost — you pay OpenAI directly. If a video has captions, the key isn't used. The captions-only mode skips Whisper entirely so you can use the actor without an OpenAI account by setting `transcriptMethod=captions` and pasting any non-empty placeholder.

**Why is `maxDurationMinutes` capped at 18 by default?** OpenAI Whisper's hard limit is 25 MB per request. 18 minutes of audio at typical bitrates is comfortably under. If you raise the cap, you may hit `audio-exceeds-whisper-limit` skips on high-bitrate music videos.

**Can I scrape playlists or channels?** Not in v1 — single video URLs only. Workaround: use Apify's other YouTube actors to extract video URLs from a playlist/channel, then pipe them into this one.

**What about livestreams?** Active livestreams are skipped with reason `live-stream`. Concluded livestream archives may work but are not explicitly tested.

**What about private/age-restricted videos?** They produce `video-unavailable` skip records. The actor never tries to authenticate.

**The actor returned a `whisper-api-error:402-insufficient-quota` skip — what now?** Your OpenAI account is out of credit. Top up at platform.openai.com — the actor side cost is unaffected.

**Can I get SRT/VTT subtitle files?** Not in v1. JSON output gives you per-segment timestamps that you can convert client-side.

### Legal

This actor accesses publicly available YouTube content. Scraping public data is generally permissible per *hiQ Labs v. LinkedIn* (2022). The actor does not log in, bypass age-gates, or download from private/restricted videos. For commercial uses, consult your own legal counsel — this is not legal advice. GDPR: video metadata may include creator names (public usernames); aggregate anonymized analysis is generally safe.

# Actor input Schema

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

YouTube video URLs (any standard format) or bare 11-character video IDs. Each URL is canonicalized + validated against a strict hostname allowlist before any download.

## `preferredLanguage` (type: `string`):

BCP-47 language code (e.g. 'en', 'es', 'fr'). When the requested caption language isn't available, the actor falls through to Whisper.

## `transcriptMethod` (type: `string`):

auto = captions first, fall through to Whisper. captions = captions only. whisper = Whisper only.

## `openaiApiKey` (type: `string`):

Your OpenAI API key. Optional — only needed when a video has no captions in your preferred language and you want Whisper to transcribe it. With no key: captions still work; videos without captions are skipped with a clear reason. The key is never logged or stored. Required only when transcriptMethod='whisper'.

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

OpenAI Whisper model. Only whisper-1 supports verbose\_json segment timestamps required by the JSON output format.

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

text = plain transcript. json = array of {start, end, text} segments.

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

When outputFormat=text, prefix each segment with \[HH:MM:SS]. Has no effect on JSON output (timestamps always present there).

## `maxDurationMinutes` (type: `integer`):

Skip videos longer than this. Default 18 to keep audio under OpenAI Whisper's 25 MB hard limit even at higher bitrates.

## `maxWhisperMinutesPerRun` (type: `integer`):

Cap on total minutes of audio sent to Whisper. Bounds your OpenAI bill per run. Set 0 for unlimited.

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

Apify proxy. RESIDENTIAL is the default — YouTube blocks datacenter IPs aggressively in 2026.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "preferredLanguage": "en",
  "transcriptMethod": "auto",
  "whisperModel": "whisper-1",
  "outputFormat": "text",
  "includeTimestamps": false,
  "maxDurationMinutes": 18,
  "maxWhisperMinutesPerRun": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

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

# Run the Actor and wait for it to finish
run = client.actor("prodiger/youtube-transcriber").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call prodiger/youtube-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=prodiger/youtube-transcriber",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Transcriber",
        "description": "Transcribe YouTube videos. Captions when available, OpenAI Whisper fallback (BYOK) for the rest. No YouTube account needed.",
        "version": "0.2",
        "x-build-id": "wmmcWxuPrAUco9Yj4"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/prodiger~youtube-transcriber/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-prodiger-youtube-transcriber",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/prodiger~youtube-transcriber/runs": {
            "post": {
                "operationId": "runs-sync-prodiger-youtube-transcriber",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/prodiger~youtube-transcriber/run-sync": {
            "post": {
                "operationId": "run-sync-prodiger-youtube-transcriber",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "videoUrls"
                ],
                "properties": {
                    "videoUrls": {
                        "title": "Video URLs",
                        "type": "array",
                        "description": "YouTube video URLs (any standard format) or bare 11-character video IDs. Each URL is canonicalized + validated against a strict hostname allowlist before any download.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "preferredLanguage": {
                        "title": "Preferred caption language",
                        "type": "string",
                        "description": "BCP-47 language code (e.g. 'en', 'es', 'fr'). When the requested caption language isn't available, the actor falls through to Whisper.",
                        "default": "en"
                    },
                    "transcriptMethod": {
                        "title": "Transcript method",
                        "enum": [
                            "auto",
                            "captions",
                            "whisper"
                        ],
                        "type": "string",
                        "description": "auto = captions first, fall through to Whisper. captions = captions only. whisper = Whisper only.",
                        "default": "auto"
                    },
                    "openaiApiKey": {
                        "title": "OpenAI API key (optional)",
                        "type": "string",
                        "description": "Your OpenAI API key. Optional — only needed when a video has no captions in your preferred language and you want Whisper to transcribe it. With no key: captions still work; videos without captions are skipped with a clear reason. The key is never logged or stored. Required only when transcriptMethod='whisper'."
                    },
                    "whisperModel": {
                        "title": "Whisper model",
                        "enum": [
                            "whisper-1"
                        ],
                        "type": "string",
                        "description": "OpenAI Whisper model. Only whisper-1 supports verbose_json segment timestamps required by the JSON output format.",
                        "default": "whisper-1"
                    },
                    "outputFormat": {
                        "title": "Output format",
                        "enum": [
                            "text",
                            "json"
                        ],
                        "type": "string",
                        "description": "text = plain transcript. json = array of {start, end, text} segments.",
                        "default": "text"
                    },
                    "includeTimestamps": {
                        "title": "Include timestamps in text output",
                        "type": "boolean",
                        "description": "When outputFormat=text, prefix each segment with [HH:MM:SS]. Has no effect on JSON output (timestamps always present there).",
                        "default": false
                    },
                    "maxDurationMinutes": {
                        "title": "Max video duration (minutes)",
                        "minimum": 1,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Skip videos longer than this. Default 18 to keep audio under OpenAI Whisper's 25 MB hard limit even at higher bitrates.",
                        "default": 18
                    },
                    "maxWhisperMinutesPerRun": {
                        "title": "Max Whisper minutes per run",
                        "minimum": 0,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Cap on total minutes of audio sent to Whisper. Bounds your OpenAI bill per run. Set 0 for unlimited.",
                        "default": 60
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy. RESIDENTIAL is the default — YouTube blocks datacenter IPs aggressively in 2026.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
