subprocess is not a video downloading strategy
The typical Python approach is subprocess.run() or subprocess.Popen() shelling out to yt-dlp:
Fine on a server where you control the environment. Not fine on Lambda, Cloud Run, or anywhere that doesn't let you install binaries. And even where it does work, you own the update cycle — yt-dlp releases frequently, and a stale build silently fails when a platform updates their extraction logic.
The API version is just requests.post().
Setup
Basic download
Usage:
The output key follows the input key: in_video → out_video, in_clip → out_clip. Whatever comes after in_ becomes the out_ key.
Tagging jobs with metadata
Pass up to 10 key/value pairs in metadata:
Metadata comes back in poll responses and webhooks.
Full client class
Usage:
Async with httpx
If you're running FastAPI or anything asyncio-based:
Parallel downloads
Submit all jobs first, then poll concurrently with asyncio:
Download and process
For downloading and immediately transcoding in one call, use download_and_process() from the client class above — it hits /run-ytdlp-command with your FFmpeg command. More recipes in the download and process guide.
FAQ
Which Python versions does this support?
Python 3.10+ for the dict[str, str] type hints. Replace with Dict from typing for older versions.
Does this work in Django or Flask?
Yes. Call download_video() from your view, or better, kick it off via Celery and return the command_id to the client immediately — don't block a request thread waiting on a 30-second download.
How do I handle rate limits?
Check response.headers["X-RateLimit-Remaining"] before batching. If you're near the limit, sleep between submissions.
Can I save the downloaded file locally?
You get a URL from the API. Fetch it to disk with: