๐ Get the Youbtube Video Downloader
For most public YouTube videos, this works fine:
yt-dlp -f "bv*+ba/best" \
--merge-output-format mp4 \
"https://www.youtube.com/watch?v=VIDEO_ID"-f "bv*+ba/best"โ pick best video + best audio.--merge-output-format mp4โ final file is MP4 even if YouTube offers WebM.
YouTube serves every video in multiple delivery protocols:
-
DASH (default) โ uses
videoplayback?...range=...URLs.- Pros: more quality choices.
- Cons: sometimes 403s if a range expires.
-
HLS (m3u8 playlists) โ chunked
.ts/.mp4streams.- Pros: more resilient, rarely 403s.
- Cons: fewer quality tiers in some cases.
๐ Thatโs why you sometimes see:
ERROR: unable to download video data: HTTP Error 403: Forbidden
The fix is to have fallback commands to switch protocols and adjust retry behavior.
yt-dlp -f "bv*+ba/best" -N 16 \
--merge-output-format mp4 \
"https://www.youtube.com/watch?v=VIDEO_ID"-N 16โ download 16 fragments at once (faster).- โ Try this first โ usually works.
yt-dlp -f "bv*[protocol=m3u8]+ba[protocol=m3u8]/best" \
--hls-prefer-native -N 16 \
--merge-output-format mp4 \
"https://www.youtube.com/watch?v=VIDEO_ID"- Switches to
.m3u8streams. - โ Best fallback when DASH fails.
yt-dlp -f "bv*[protocol=m3u8]+ba[protocol=m3u8]/best" \
--hls-prefer-native -N 16 \
--retries 20 --fragment-retries 100 \
--merge-output-format mp4 \
"https://www.youtube.com/watch?v=VIDEO_ID"- Retries aggressively if any chunk fails.
- โ Good for long/high-bitrate videos.
First install aria2:
brew install aria2Then run:
yt-dlp -f "bv*+ba/best" \
--downloader aria2c \
--downloader-args "aria2c:-x 16 -s 16 -k 1M --max-tries=0 --retry-wait=5" \
--merge-output-format mp4 \
"https://www.youtube.com/watch?v=VIDEO_ID"-x 16 -s 16โ 16 parallel connections.- Retries indefinitely until the file completes.
- โ Almost bulletproof, even on unstable networks.
-
Clear cache if signatures go stale:
yt-dlp --rm-cache-dir
-
Age-restricted or region-locked videos: Use cookies from your browser:
yt-dlp --cookies-from-browser "chrome:Default" "URL"
-
Specific resolution:
yt-dlp -f "bv*[height=1080]+ba/best" "URL"
-
yt-dlp is the tool to use for YouTube โ there isnโt a better maintained alternative.
-
Sometimes downloads 403 mid-way because YouTubeโs CDN rejects DASH requests.
-
Solution: keep a 4-step playbook:
- Normal DASH with concurrency.
- HLS fallback.
- HLS + retries.
- aria2c external downloader.
With this sequence, youโll succeed in almost every case.
Great question ๐
Unfortunately, yt-dlp itself doesnโt have a built-in โtry this, and if it fails, try thatโ fallback sequence. It will either succeed or exit with an error. But you can string your four approaches together in one shell command using || (OR chaining).
That way, if the first command fails, the shell runs the next one automatically.
yt-dlp -f "bv*+ba/best" -N 16 --merge-output-format mp4 "https://www.youtube.com/watch?v=VIDEO_ID" \
|| yt-dlp -f "bv*[protocol=m3u8]+ba[protocol=m3u8]/best" --hls-prefer-native -N 16 --merge-output-format mp4 "https://www.youtube.com/watch?v=VIDEO_ID" \
|| yt-dlp -f "bv*[protocol=m3u8]+ba[protocol=m3u8]/best" --hls-prefer-native -N 16 --retries 20 --fragment-retries 100 --merge-output-format mp4 "https://www.youtube.com/watch?v=VIDEO_ID" \
|| yt-dlp -f "bv*+ba/best" --downloader aria2c --downloader-args "aria2c:-x 16 -s 16 -k 1M --max-tries=0 --retry-wait=5" --merge-output-format mp4 "https://www.youtube.com/watch?v=VIDEO_ID"-
cmd1 || cmd2 || cmd3 ...Shell runscmd1.- If it succeeds โ stop.
- If it fails (non-zero exit code) โ run the next one.
So this tries:
- Normal DASH with concurrency.
- HLS fallback.
- HLS with retries.
- aria2c external downloader.
Whichever works first will complete the download.
Yep โ you can chain them, but itโs cleaner to try max-quality (MKV, AV1/VP9 OK) first, then fall back to MP4-only variants, with HLS + retries, and finally aria2c. Hereโs a single paste-and-go you can reuse.
VIDEO_URL="https://www.youtube.com/watch?v=S-mow-gu2XA"; \
yt-dlp -N 16 -f "bestvideo*+bestaudio/best" \
--remux-video mkv "$VIDEO_URL" \
|| yt-dlp -N 16 -f "bv*+ba/best" \
--http-chunk-size 10M --retries 20 --fragment-retries 100 --force-ipv4 \
--remux-video mkv "$VIDEO_URL" \
|| yt-dlp -N 16 -f "bv*[protocol=m3u8]+ba[protocol=m3u8]/best" \
--hls-prefer-native --retries 20 --fragment-retries 100 \
--remux-video mkv "$VIDEO_URL" \
|| yt-dlp -N 16 -f "bv*[ext=mp4][vcodec*=avc1]+ba[ext=m4a]/best[ext=mp4]" \
--merge-output-format mp4 "$VIDEO_URL" \
|| yt-dlp -f "bv*+ba/best" \
--downloader aria2c \
--downloader-args "aria2c:-x 16 -s 16 -k 1M --max-tries=0 --retry-wait=5" \
--merge-output-format mp4 "$VIDEO_URL"- Max quality (DASH) โ grabs AV1/VP9 + best audio, remux to MKV (keeps 4K/HDR).
- DASH w/ tougher HTTP โ smaller chunks, retries, IPv4; still MKV so high tiers are allowed.
- Force HLS โ more resilient when DASH 403s; remux MKV (usually โค1080p).
- MP4-only โ AVC + M4A for widest compatibility (often โค1080p).
- Aria2c fallback โ segmented downloader with infinite retries; outputs MP4.
- Change
VIDEO_URLonce; the chain reuses it. - Want a specific res for MKV path? e.g., 2160p:
-f "bestvideo*[height=2160]+bestaudio/best". - Add an output template if you want a specific filename/path:
-o "%(title)s.%(ext)s". - If a password/exclamation ever appears in args, quote it with single quotes in zsh.