YouTube Download API
Send a list of YouTube links and get the media back as files. Video from 144p to 4K with sound always included, or audio as M4A, MP3 or Opus. Each link returns one row with a file link, file size, SHA-256 checksum, duration and channel details. Files land in the run's storage or straight in your own Amazon S3, Google Cloud Storage or Azure bucket. Billing is per minute of media delivered; private, removed, blocked and skipped videos are free rows with a plain error code.
Input parameters
| PARAMETER | TYPE | REQ | DEFAULT | DESCRIPTION |
|---|---|---|---|---|
| videoUrls | string[] | yes | [https://www.youtube.com/watch?v=jNQXAC9IVRw] | YouTube links or 11-character video ids. Watch, youtu.be, Shorts, embed and live-replay links all work. Up to 200 per run. — drives your bill |
| format | enum | no | audio | audio · video. Video always includes sound. — drives your bill |
| quality | enum | no | 720p | 144p · 240p · 360p · 480p · 720p · 1080p · 1440p · 2160p. A ceiling; if the video tops out lower, the best available quality is delivered and billed at its own rate. — drives your bill |
| audioFormat | enum | no | m4a | m4a · mp3 · opus. M4A and Opus are delivered without re-encoding. |
| audioQuality | enum | no | standard | standard (compact, clear for speech) · high (best available). |
| videoCodec | enum | no | smallest | smallest (AV1 or VP9 when offered) · h264 (plays everywhere, up to 1080p). |
| metadataOnly | boolean | no | — | Return title, duration, available qualities and estimated sizes without downloading. Free. |
| maxMinutes | integer | no | — | Skip videos longer than this, at no charge, before anything is downloaded. |
| maxMegabytes | integer | no | — | Skip files estimated to be larger than this, at no charge. |
| storageProvider | enum | no | apify | apify · s3 · gcs · azure. Send files to your own bucket instead of the run's key-value store. Billed per megabyte of each upload attempted. — drives your bill |
| cookies | string | no | — | Optional cookies from your own signed-in session, only for age-restricted or members-only videos you have access to. Stored as a secret. |
Output schema
| FIELD | TYPE | DESCRIPTION | NULLABLE |
|---|---|---|---|
| resultType | string | file · metadata · skipped · error. Only file rows are charged. | no |
| videoId | string | YouTube video id. | yes |
| url | string | Canonical watch link. | yes |
| title | string | Video title. | yes |
| channelName | string | Channel that published the video. | yes |
| durationSeconds | integer | Length of the video in seconds. | yes |
| format | string | audio or video. | yes |
| quality | string | Delivered quality, audio or a height such as 720p. This is what is billed. | yes |
| container | string | mp4, webm, mkv, m4a, mp3 or opus. | yes |
| videoCodec | string | av1, vp9 or h264. | yes |
| audioCodec | string | aac, opus or mp3. | yes |
| fileUrl | string | Link to the file in the run's key-value store, or the object's address in your own bucket. | yes |
| fileSizeBytes | integer | Size of the delivered file. | yes |
| sha256 | string | SHA-256 checksum of the delivered file. | yes |
| storage | string | apify, s3, gcs or azure. | yes |
| storageUri | string | Object address in your own storage, such as s3://bucket/key. | yes |
| chargedEvent | string | The event this file was billed under. | yes |
| chargedMinutes | integer | Minutes billed, the duration rounded up. | yes |
| availableQualities | string[] | Metadata rows, every video quality on offer. | yes |
| estimatedSizeBytes | object | Metadata rows, estimated file size per quality and for audio. | yes |
| error | string | Error code on error and skipped rows, such as VIDEO_UNAVAILABLE, VIDEO_PRIVATE, AGE_RESTRICTED or OVER_MAX_MINUTES. | yes |
| errorMessage | string | Plain explanation on error and skipped rows. | yes |
Worked examples
{ "videoUrls": ["https://www.youtube.com/watch?v=aqz-KE-bpKQ"], "format": "audio" }
{
"videoUrls": ["https://youtu.be/aqz-KE-bpKQ"],
"format": "video",
"quality": "720p",
"videoCodec": "h264"
}
{ "videoUrls": ["aqz-KE-bpKQ", "jNQXAC9IVRw"], "metadataOnly": true }
{
"videoUrls": ["https://www.youtube.com/watch?v=aqz-KE-bpKQ"],
"format": "video",
"storageProvider": "s3",
"storageBucket": "my-video-archive",
"storageRegion": "us-east-1",
"storageAccessKeyId": "YOUR_ACCESS_KEY_ID",
"storageSecretAccessKey": "YOUR_SECRET_ACCESS_KEY"
}
Coverage
Code
curl
curl -X POST "https://api.apify.com/v2/acts/johnvc~youtube-download-api/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"videoUrls":["https://www.youtube.com/watch?v=jNQXAC9IVRw"],"format":"audio"}'
Python
from apify_client import ApifyClient
client = ApifyClient("APIFY_TOKEN")
run = client.actor("johnvc/youtube-download-api").call(
run_input={
"videoUrls": ["https://www.youtube.com/watch?v=aqz-KE-bpKQ"],
"format": "audio",
}
)
for row in client.dataset(run.default_dataset_id).iterate_items():
print(row.get("title"), row.get("fileUrl"), row.get("sha256"))
MCP
claude mcp add --transport http youtube-download \ "https://mcp.apify.com/?tools=actors,docs,johnvc/youtube-download-api"
What people use it for
- Archiving your own channel with checksums
- Audio for transcription, summarization and RAG pipelines
- Lectures, talks and webinars for offline study
- Video datasets for machine learning
- Research and media monitoring with a metadata row per video
- Agents that need the media file itself, over MCP
More sources for Transcripts, images and content pipelines, Grounding AI agents and MCP tools →
Alternatives
Use it from an MCP client
Add the Apify MCP server to any MCP client and this API becomes a tool the assistant can call. The server URL is https://mcp.apify.com/?tools=actors,docs,johnvc/youtube-download-api. It works with Claude Code (free trial), Claude Cowork (free trial), Cursor and ChatGPT. Then ask in plain language: “Download the audio of this talk as M4A and give me the file link” or “Which of these ten videos are longer than an hour? Check without downloading.”