# Youtube Video Downloader (`transcriptdl/youtube-video-scraper-extractor-downloader`) Actor

Verified 99.4% Success. BULK download and scrape MP4 video files from YouTube videos using the Transcript Downloader API. Supports optional storage to Apify, webhook delivery, and progress tracking with automatic polling.

- **URL**: https://apify.com/transcriptdl/youtube-video-scraper-extractor-downloader.md
- **Developed by:** [Transcript Downloader](https://apify.com/transcriptdl) (community)
- **Categories:** AI, Automation, Social media
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## 🎬 Transcript Downloader - Youtube Video Scraper & Downloader

Convert YouTube videos into downloadable MP4 files using the Transcript Downloader API. Ideal for offline viewing, content archiving, and video repurposing. Works in bulk, with optional storage to Apify key-value store.

---

### ✨ Features

* 📁 **Bulk processing** of multiple YouTube video IDs
* 🕒 **Polling logic** with automatic retries
* 🧠 **Progress tracking** and run logs
* 🗂️ **Optional Apify file storage** to key-value store
* 🔔 **Webhook support**: Receive results via webhook instead of polling
* 🔐 **Secure API token-based authentication**

---

### 🔧 Input Parameters

| Parameter         | Type    | Required | Default | Description                                                      |
| ----------------- | ------- | -------- | ------- | ---------------------------------------------------------------- |
| `videoIds`        | array   | ✅ Yes    | –       | List of YouTube video IDs to process                             |
| `apiToken`        | string  | ✅ Yes    | –       | Bearer token for Transcript Downloader API                       |
| `downloadToApify` | boolean | No       | `true`  | Whether to download MP4 files to Apify key-value store           |
| `maxWaitTime`     | number  | No       | `15`    | Max time to wait for video processing (in minutes, range: 1–30)  |
| `pollingInterval` | number  | No       | `60`    | Interval between polling status (in seconds, range: 30–300)      |
| `includeWebhook`  | string  | No       | –       | Webhook URL to receive results when video processing completes. Must be publicly reachable and accept POST requests |

📥 **Example Input**

```json
{
  "videoIds": ["Fqdz6A-5d04"],
  "apiToken": "your-api-token",
  "downloadToApify": true,
  "maxWaitTime": 15,
  "pollingInterval": 60
}
````

***

### 📤 Output Format

Each video generates an output record with metadata and processing info:

```json
{
  "youtube_id": "Fqdz6A-5d04",
  "id": "01JW72M0AGW3M6R3QDCS30RD2P",
  "media_id": "abc123",
  "type": "youtube_video",
  "duration": "01:47:55",
  "cost": "1.079",
  "status": "success",
  "file_urls": ["https://drive.transcriptdownloader.com/videos/youtube-Fqdz6A-5d04.mp4?Expires=..."],
  "created_at": "2025-01-23T00:30:50.000Z",
  "storage_key": "video-Fqdz6A-5d04.mp4"
}
```

***

### 🚀 How to Use

1. Get your API token from [Transcript Downloader](https://dashboard.transcriptdownloader.com/settings)
2. Add one or more YouTube video IDs (11-character alphanumeric IDs, e.g. `Fqdz6A-5d04`)
3. Set `downloadToApify` to `true` if you want MP4 files saved to Apify key-value store
4. Run the actor and access results in the dataset or key-value store

#### Supported Video ID Format

YouTube video IDs are exactly **11 characters** long and contain only letters, numbers, hyphens, and underscores (e.g. `Fqdz6A-5d04`). You can find the ID in any YouTube URL after `?v=` or `/shorts/`.

***

### ❌ Error Handling

This actor includes robust handling for common issues:

| Status Code | Description                                             |
| ----------- | ------------------------------------------------------- |
| `401`       | Invalid API key – check or regenerate your token        |
| `422`       | Video unavailable or cannot be processed                |
| `429`       | Too many requests – reduce polling frequency            |
| `503`       | Transcript Downloader API under maintenance             |
| Custom      | `"You already have a pending download for this video"`  |

If a video is already being processed, its ID will be extracted from the error response and polling will continue automatically.

***

### ⚠️ Rate Limiting & Performance

#### API Rate Limits

| Scope | Limit | Window |
| ----- | ----- | ------ |
| Per User (API Token) | 90 requests | 1 minute |
| Per IP (unauthenticated) | 90 requests | 1 minute |

When rate limits are exceeded, the API returns `429 Too Many Requests`. The actor handles this automatically with built-in retry logic.

#### Video Download Cooldown

| Endpoint | Limit | Cooldown Period | Scope |
| -------- | ----- | --------------- | ----- |
| Single Video Download | 1 request | 5 minutes | Per video |

If you request video for the same video within the 5-minute cooldown, the API returns a pending download response. The actor handles duplicate requests gracefully by extracting the existing download ID and continuing to poll.

#### Processing Times

| Scenario | Typical Duration | Maximum Wait |
| -------- | ---------------- | ------------ |
| Short videos (< 10 min) | < 1 minute | 30 minutes |
| Medium videos (10-60 min) | 1-5 minutes | 30 minutes |
| Long videos (60+ min) | 5-20 minutes | 30 minutes |

#### Retry Behavior

The actor automatically retries on transient errors (429, 500, 503) with exponential backoff (base delay 2s, up to 3 attempts). It does **not** retry on client errors (401, 403, 422) since those require user action.

#### Response Headers

The API returns rate limit headers you can monitor in logs:

| Header | Description |
| ------ | ----------- |
| `X-RateLimit-Limit` | Max requests allowed in window |
| `X-RateLimit-Remaining` | Requests remaining in current window |
| `Retry-After` | Seconds to wait before retrying (on 429) |

***

### 🔔 Webhook Support

Instead of polling, you can receive results automatically via webhook. Pass a publicly reachable URL in the `includeWebhook` field, and the API will POST the results directly to your server when video processing completes.

#### How It Works

1. The webhook URL is sent with the **initial API request only** (not during polling)
2. One webhook is fired per video when processing completes or fails
3. The webhook payload is the exact same JSON the API endpoint would return
4. Failed deliveries are retried up to 3 times (at 10s, 30s, and 60s intervals)

#### Webhook Headers

Each delivery includes these custom headers to identify the event:

| Header | Description |
| ------ | ----------- |
| `X-Webhook-Endpoint` | `downloads/video` |
| `X-Webhook-Original-Status` | HTTP status code of the result (e.g. `200`) |
| `X-Webhook-Download-Id` | The download record ID |

#### Example with Webhook

```json
{
  "videoIds": ["Fqdz6A-5d04"],
  "apiToken": "your-token",
  "includeWebhook": "https://your-domain.com/webhook"
}
```

#### Important Notes

- The URL must be publicly reachable (no localhost or private IPs)
- Your endpoint must accept **POST** requests and return a `2xx` status
- Test your webhook URL first using the [API test endpoint](https://documentation.transcriptdownloader.com)
- The webhook is registered once at request time — it cannot be added after a job has started

***

### 💡 Best Practices

- ✅ Respect rate limits to avoid 429 errors
- ⏳ Use polling wisely — longer intervals for large queues
- ⏳ Avoid re-requesting the same video within the 5-minute cooldown
- 🔐 Keep your `apiToken` secret (never log it)
- 🧠 Monitor output for incomplete or failed downloads
- 🗂️ Store large video files in Apify only when needed — allocate at least 2GB memory for long videos

***

### 📈 Monitoring

Track performance and usage with Apify tools:

- Run history
- Success/failure rates
- Storage and resource usage
- Output file availability

***

### 💳 Pricing & Billing

The Transcript Downloader API used by this actor requires a valid API token.
API usage is billed separately and is based on processing time and file size.

📊 We charge per minute of video. Visit our site to checkout pricing.
View full details and subscription plans on our [pricing page](https://transcriptdownloader.com/#pricing)

***

### 🙋 Support

Need help? Visit [Transcript Downloader Support](https://www.transcriptdownloader.com/#contact).
We respond within 24 business hours.

***

### 📄 License

This actor is provided under the [ISC License](https://opensource.org/licenses/ISC).

# Actor input Schema

## `videoIds` (type: `array`):

List of YouTube video IDs to download as MP4

## `apiToken` (type: `string`):

Bearer token for Transcript Downloader API authentication

## `downloadToApify` (type: `boolean`):

Whether to download MP4 files to Apify key-value store

## `maxWaitTime` (type: `integer`):

Maximum time to wait for video processing (1-30 minutes)

## `pollingInterval` (type: `integer`):

How often to check download status (minimum 30 seconds due to rate limits)

## `includeWebhook` (type: `string`):

Optional webhook URL to receive results when video processing completes. Must be a publicly reachable URL that accepts POST requests.

## Actor input object example

```json
{
  "downloadToApify": true,
  "maxWaitTime": 15,
  "pollingInterval": 60
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("transcriptdl/youtube-video-scraper-extractor-downloader").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("transcriptdl/youtube-video-scraper-extractor-downloader").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 '{}' |
apify call transcriptdl/youtube-video-scraper-extractor-downloader --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Youtube Video Downloader",
        "description": "Verified 99.4% Success. BULK download and scrape MP4 video files from YouTube videos using the Transcript Downloader API. Supports optional storage to Apify, webhook delivery, and progress tracking with automatic polling.",
        "version": "1.0",
        "x-build-id": "zyofdbg5oUugB0G1f"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/transcriptdl~youtube-video-scraper-extractor-downloader/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-transcriptdl-youtube-video-scraper-extractor-downloader",
                "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/transcriptdl~youtube-video-scraper-extractor-downloader/runs": {
            "post": {
                "operationId": "runs-sync-transcriptdl-youtube-video-scraper-extractor-downloader",
                "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/transcriptdl~youtube-video-scraper-extractor-downloader/run-sync": {
            "post": {
                "operationId": "run-sync-transcriptdl-youtube-video-scraper-extractor-downloader",
                "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": [
                    "videoIds",
                    "apiToken"
                ],
                "properties": {
                    "videoIds": {
                        "title": "YouTube Video IDs",
                        "type": "array",
                        "description": "List of YouTube video IDs to download as MP4",
                        "items": {
                            "type": "string"
                        }
                    },
                    "apiToken": {
                        "title": "API Bearer Token",
                        "type": "string",
                        "description": "Bearer token for Transcript Downloader API authentication"
                    },
                    "downloadToApify": {
                        "title": "Download to Apify Storage",
                        "type": "boolean",
                        "description": "Whether to download MP4 files to Apify key-value store",
                        "default": true
                    },
                    "maxWaitTime": {
                        "title": "Maximum Wait Time (minutes)",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Maximum time to wait for video processing (1-30 minutes)",
                        "default": 15
                    },
                    "pollingInterval": {
                        "title": "Polling Interval (seconds)",
                        "minimum": 30,
                        "maximum": 300,
                        "type": "integer",
                        "description": "How often to check download status (minimum 30 seconds due to rate limits)",
                        "default": 60
                    },
                    "includeWebhook": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "Optional webhook URL to receive results when video processing completes. Must be a publicly reachable URL that accepts POST requests."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
