The short version
RenderIO gives you a hosted yt-dlp API. Send a public video URL to POST /api/v1/ytdlp-download, poll the returned command_id, and read the final file URL from output_files.out_video.storage_url.
Use POST /api/v1/run-ytdlp-command when you want to download the public video and immediately run FFmpeg on it for audio extraction, trimming, resizing, compression, thumbnails, or any other post-processing step.
yt-dlp is a headache to run in production
Running yt-dlp on your own machine is fine. Running it as part of a real service is something else.
Platforms change their extraction logic all the time, so you're constantly chasing yt-dlp updates just to stay functional. You need residential or rotating proxies or you'll get IP-banned. Serverless platforms can't run binaries at all. And all the retry and rate-limit logic falls on you.
The RenderIO yt-dlp API handles that stack. You POST a URL, you get back a stored media file. Here's how.
What the API does
The API accepts a public video URL, downloads it via yt-dlp, and stores the result. It supports YouTube, TikTok, Instagram, X/Twitter, Reddit, Vimeo, Twitch, Facebook, and thousands of yt-dlp extractors.
Private videos, DRM-protected content, paywalled content, and anything behind a login wall return an error. Public content only.
Two endpoints:
POST /api/v1/ytdlp-download— download, no post-processingPOST /api/v1/run-ytdlp-command— download, then optionally run an FFmpeg command on the result
Both are async: submit, get a command_id, poll for the result.
The full endpoint docs live in the yt-dlp download API reference, the download + process API reference, and the yt-dlp docs guide.
Your first download
You get back:
Poll for status:
When it finishes:
The file URL is at output_files.out_video.storage_url. The output key is derived from your input key: in_video → out_video, in_clip → out_clip.
The input_urls key format
Keys must start with in_. Whatever comes after the underscore becomes the out_ key in the response.
→ output_files.out_clip.storage_url
Pick a name that makes sense for your code. in_video, in_clip, in_source — all valid.
Polling
Status values: QUEUED, PROCESSING, SUCCESS, FAILED.
Most downloads wrap up in 10-60 seconds. Larger files take longer, as you'd expect.
Metadata
Pass up to 10 key/value pairs in metadata to tag the job with your own identifiers — user IDs, job references, whatever you need for correlation later.
It comes back in poll responses and webhooks.
Download and process in one call
Need to transcode the video right after downloading? Use /api/v1/run-ytdlp-command instead. It downloads first, then runs your FFmpeg command on the result.
{{double_braces}} for placeholders. output_files maps each output key to a filename. Skip ffmpeg_command entirely and it behaves like the plain download endpoint.
More recipes in the download and process guide.
When things fail
If the URL is unavailable or unsupported, the poll response returns status: "FAILED":
The usual culprits: the video was deleted or is private, the platform requires a login, the URL format isn't something yt-dlp recognizes, or the platform temporarily rate-limited the request (retry usually works for the last one).
Rate limits
Your plan determines the limit. Check X-RateLimit-Remaining in response headers before batching a lot of requests.
Language-specific guides
Full examples with polling and error handling for:
Node.js — fetch-based, works on any serverless platform
Python — requests-based with a complete client class
Supported platforms
| Platform | Notes |
| YouTube | Public videos, Shorts, playlists (one URL per call) |
| TikTok | Public posts only |
| Public posts and Reels | |
| X/Twitter | Public posts with video |
| Video posts | |
| Vimeo | Public videos |
| Twitch | VODs and clips |
| Public videos |
The yt-dlp supported sites list changes over time. The upstream project notes that websites change and listed extractors are not guaranteed forever, so your application should handle FAILED command responses and retries.
Age-gated content and anything requiring a login may fail. DRM-protected and paywalled content is not supported.
FAQ
Does this support downloading entire YouTube playlists?
Not as automatic playlist expansion. For playlists, iterate over the individual video URLs and submit them separately. For tracking and retries, one URL per command is usually easiest, though the API accepts multiple input_urls keys in one payload.
What format does the downloaded video come in?
yt-dlp picks the best available format, usually MP4 with H.264 video and AAC audio. If you need something specific, use the run-ytdlp-command endpoint and add an FFmpeg transcode step.
Can I call this from a serverless function?
Yes. It's just HTTP. Works from Lambda, Cloudflare Workers, Vercel — anything with outbound requests.
Start here
Get an API key if you do not have one yet.
Read the yt-dlp API guide for cURL, Python, and Node.js examples.
Use the API reference when wiring this into production.