# Youtube Video Downloader - No Platform Costs! No Proxy Costs! (`epctex/youtube-video-downloader`) Actor

Download YouTube videos by URL or ID at any quality from 360p to 4K. Save to Apify's built-in storage with zero setup, or to your own AWS S3, Google Cloud, DigitalOcean, or Azure. Pay-per-event, per-second pricing with no platform or proxy costs - know your exact cost before every run.

- **URL**: https://apify.com/epctex/youtube-video-downloader.md
- **Developed by:** [epctex](https://apify.com/epctex) (community)
- **Categories:** Videos, Social media, Automation
- **Stats:** 5,115 total users, 392 monthly users, 98.8% runs succeeded, 125 bookmarks
- **User rating**: 2.22 out of 5 stars

## Pricing

from $0.15 / 1,000 360p one seconds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## YouTube Video Downloader — No Platform Costs! No Proxy Costs!

Download videos from YouTube at the quality you choose and save them to Apify's built-in storage with zero setup — or deliver them to your own cloud: AWS S3, Google Cloud, DigitalOcean Spaces, or Azure.

Since YouTube doesn't offer a free, reliable API for downloading videos, this actor handles it for you: give it video URLs or IDs, pick a resolution, and get back a direct link to each downloaded file.

**Pay-per-event pricing with no platform or proxy costs** — every event has a fixed price, so you know exactly what you'll pay before you start a run.

### Features

- Download by video **URL** or **video ID** (`watch` links, `youtu.be`, Shorts, and embeds supported)
- Choose resolution from **360p up to 4K (2160p)**
- Save to **Apify's key-value store out of the box** (no cloud account needed) — or bring your own **AWS S3, Google Cloud, DigitalOcean Spaces, or Azure**
- Clean JSON output with a direct download URL and a per-video cost breakdown
- Optionally **send the results to Notion, Todoist and more** through your own [MCP connector](#send-results-to-notion-todoist-and-more)

### Input

| Field         | Type   | Required | Description                                                          |
| ------------- | ------ | -------- | -------------------------------------------------------------------- |
| `startUrls`   | array  | Yes\*    | YouTube video URLs to download.                                      |
| `videoIds`    | array  | Yes\*    | YouTube video IDs to download.                                       |
| `quality`     | string | Yes      | Target resolution: `360`, `480`, `720`, `1080`, `1440`, `2160`. Default `720`. |
| `storageType` | string | Yes      | Where to store files: `apify`, `aws`, `gcp`, `digitalocean`, `azure`. Default `apify`. |

| `outputConnector` | string | No | MCP connector to deliver the results to (see [Send Results to Notion, Todoist and More](#send-results-to-notion-todoist-and-more)). |
| `deliverTarget` | string | No | Where the connector writes — paste the URL or ID (Notion example: `https://www.notion.so/My-Videos-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b`); some services need none. |
| `deliverMode` | string | No | `perPost` (one record per video) or `summary` (one roll-up per run). Default `perPost`. |
| `deliverMaxItems` | integer | No | Cap on how many records `perPost` delivers (ignored in `summary`). |

\*Provide at least one of `startUrls` or `videoIds`.

#### Storage options

By default (`storageType: "apify"`), videos are saved to the run's **Apify key-value store** and you get a direct download URL in the output — no cloud account, credentials, or extra setup required. This is the simplest way to use the actor.

To deliver files to your own cloud instead, set `storageType` accordingly and fill in the matching configuration:

- **AWS S3:** `s3AccessKeyId`, `s3SecretAccessKey`, `s3Region`, `s3Bucket`, `s3Path` (optional)
- **Google Cloud:** `googleCloudProjectId`, `googleCloudServiceKeyJson`, `googleCloudBucketName`, `googleCloudPath` (optional)
- **DigitalOcean Spaces:** `digitalOceanAccessKeyId`, `digitalOceanSecretAccessKey`, `digitalOceanRegion`, `digitalOceanBucketName`, `digitalOceanEndpoint` (optional), `digitalOceanAcl` (optional), `digitalOceanPath` (optional)
- **Azure:** `azureAccountName`, `azureAccountKey`, `azureContainerName`, `azurePath` (optional)

#### Example input

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=BB49x_uMlGA",
    "https://www.youtube.com/shorts/bOUOSn9MULw"
  ],
  "videoIds": ["etEJKUNqKJk"],
  "quality": "1080",
  "storageType": "apify"
}
```

### Pricing

Pricing is **pay-per-event**, billed **per second of video**, with **no platform or proxy costs** on top. Every event has a fixed price, so you can work out the exact cost of a run before you start it. The rate depends on the resolution you pick:

| Quality    | Price per second |
| ---------- | ---------------- |
| 360p       | $0.00015         |
| 480p       | $0.00025         |
| 720p       | $0.00045         |
| 1080p      | $0.00075         |
| 1440p      | $0.001           |
| 2160p (4K) | $0.0012          |

For example, a 10-minute (600s) video at 1080p costs `600 × $0.00075 = $0.45`.

Before downloading each video, the actor first looks up its **duration** and charges upfront for the full length at the selected quality's per-second rate. The exact `durationSeconds`, `unitPricePerSecond`, and `totalCost` are included in the output for every video.

**Free plan:** users on Apify's Free plan can initiate up to **2 runs per month**. [Subscribe to a paid plan](https://apify.com/pricing?fpr=yhdrb) for unlimited runs.

### Output

Each downloaded video is stored as one dataset item:

```json
{
  "inputSource": "https://www.youtube.com/watch?v=BB49x_uMlGA",
  "videoId": "BB49x_uMlGA",
  "quality": "1080",
  "jobId": "a1b2c3d4",
  "status": "succeeded",
  "storageType": "apify",
  "output": {
    "url": "https://api.apify.com/v2/key-value-stores/xxx/records/BB49x_uMlGA.mp4"
  },
  "durationSeconds": 215,
  "unitPricePerSecond": 0.00075,
  "totalCost": 0.16125,
  "error": null
}
```

You can fetch results in any language (Python, PHP, Node.js) via the [Apify API](https://docs.apify.com/api/v2).

### Send Results to Notion, Todoist and More

Skip the manual exports — the YouTube Video Downloader can deliver its results (video ID, status, download URL and cost) directly into the tools you already work in, through [Apify MCP Connectors](https://apify.com/store/collections/mcp-connectors). The video files themselves stay in the storage you picked; the connector receives the result records.

1. Authorize a connector (Notion, Todoist, or any service whose MCP server offers non-destructive write tools) once in [Console → Settings → API & Integrations → MCP connectors](https://console.apify.com/settings/integrations).
2. Pick it from the **Send results to Notion, Todoist, …** dropdown.
3. Fill in where and how to write:
   - **Destination target** — paste the URL or ID (Notion example: `https://www.notion.so/My-Videos-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b`); share it with your connector first via Notion's **•••  → Connections** menu. For structured columns use a **page** URL (the Actor builds the database for you) or a database that **already has columns** — an empty database only receives titles. (Some services need no target.)
   - **Write mode** — `perPost` writes one record per video; `summary` writes a single roll-up for the run.
   - **Max records to deliver** *(optional)* — cap on how many records `perPost` delivers.

**Notion, structured like a spreadsheet:** for a table of typed columns, point the target at a Notion **page** — the Actor auto-creates a database from the data, one matching, correctly-typed column per field (URL, number, date, text). Pointing at an **existing database** fills the columns it already has (matched by name); an **empty database** receives only the title, and the rest of each record goes to the row body — the connector can't add columns to an existing database without destructive access it never requests. Nested fields are flattened into columns too — the `output` object becomes an `output.url` column — so everything is sortable and filterable in the grid. Fields that don't fit a column go to the row's page body, so nothing is lost.

Your credentials stay yours: the Actor talks to your services exclusively through your own authorized connector and only ever uses non-destructive write tools — it cannot delete or overwrite anything you already have. Delivery is best-effort and runs after the downloads: if a connector is misconfigured or a delivery fails, your run still finishes normally with all results intact — the failure is reported in the run log, never by failing the run. If the run is about to hit its timeout, delivery stops early so the run still succeeds, and the log tells you how many records were delivered.

### Contact

Visit [epctex.com](https://epctex.com) to see all our products. For custom integrations or support, reach out through the chat box on [epctex.com](https://epctex.com) or email <business@epctex.com>.

# Actor input Schema

## `startUrls` (type: `array`):

List of YouTube video URLs to download. Provide either startUrls or videoIds.

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

List of YouTube video IDs to download.

## `quality` (type: `string`):

Target video quality.

## `storageType` (type: `string`):

Target storage provider. Fill the matching configuration section below.

## `s3AccessKeyId` (type: `string`):

Fill in the following fields if you want to upload the video to an S3 bucket

## `s3SecretAccessKey` (type: `string`):

Fill in the following fields if you want to upload the video to an S3 bucket

## `s3Bucket` (type: `string`):

Fill in the following fields if you want to upload the video to an S3 bucket

## `s3Region` (type: `string`):

Fill in the following fields if you want to upload the video to an S3 bucket

## `s3Path` (type: `string`):

Optional folder path in the S3 bucket.

## `googleCloudProjectId` (type: `string`):

GCP project ID.

## `googleCloudServiceKeyJson` (type: `object`):

Service account credentials JSON.

## `googleCloudBucketName` (type: `string`):

Target Google Cloud Storage bucket name.

## `googleCloudPath` (type: `string`):

Optional folder path in the GCS bucket.

## `digitalOceanAccessKeyId` (type: `string`):

DigitalOcean Spaces access key ID.

## `digitalOceanSecretAccessKey` (type: `string`):

DigitalOcean Spaces secret access key.

## `digitalOceanRegion` (type: `string`):

DigitalOcean Spaces region (e.g. nyc3).

## `digitalOceanBucketName` (type: `string`):

DigitalOcean Spaces bucket name.

## `digitalOceanEndpoint` (type: `string`):

Optional Spaces endpoint URL.

## `digitalOceanAcl` (type: `string`):

Optional ACL value (defaults to private).

## `digitalOceanPath` (type: `string`):

Optional folder path in the Spaces bucket.

## `azureAccountName` (type: `string`):

Azure storage account name.

## `azureAccountKey` (type: `string`):

Azure storage account key.

## `azureContainerName` (type: `string`):

Azure container name.

## `azurePath` (type: `string`):

Optional folder path in the Azure container.

## `outputConnector` (type: `string`):

Pick an MCP connector you authorized in Console → Settings → API & Integrations → MCP connectors (e.g. Notion, Todoist — any service whose MCP server offers non-destructive write tools works best-effort). The download results (video ID, status, download URL, cost) are written through your own connector — the Actor never sees your third-party credentials. Only non-destructive write tools are used; it can never delete or overwrite your existing data.

## `deliverTarget` (type: `string`):

Where to write into the connector — paste the URL or ID. Notion example: https://www.notion.so/My-Videos-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b. Leave empty for services that need no target (e.g. Todoist Inbox, Slack). For Notion, share the page or database with your connector first (Notion's ••• → Connections menu), and point at a PAGE for structured columns (the Actor builds the database for you) — an empty database receives only the title (the rest of each record goes to the row's body).

## `deliverMode` (type: `string`):

perPost writes one record per downloaded video; summary writes a single roll-up for the run.

## `deliverMaxItems` (type: `integer`):

Cap on how many records perPost mode writes to the connector; ignored in summary mode. Leave empty to deliver everything downloaded.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=BB49x_uMlGA"
  ],
  "videoIds": [],
  "quality": "720",
  "storageType": "apify",
  "deliverMode": "perPost"
}
```

# Actor output Schema

## `overview` (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 = {
    "startUrls": [
        "https://www.youtube.com/watch?v=BB49x_uMlGA"
    ],
    "videoIds": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("epctex/youtube-video-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 = {
    "startUrls": ["https://www.youtube.com/watch?v=BB49x_uMlGA"],
    "videoIds": [],
}

# Run the Actor and wait for it to finish
run = client.actor("epctex/youtube-video-downloader").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 '{
  "startUrls": [
    "https://www.youtube.com/watch?v=BB49x_uMlGA"
  ],
  "videoIds": []
}' |
apify call epctex/youtube-video-downloader --silent --output-dataset

```

## MCP server setup

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

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/y1IMcEPawMQPafm02/builds/8Z2xlpZaMcnbSL4HK/openapi.json
