Skip to content

yt-dlp 403 Forbidden: why it happens and the fix order that works

By Tunelio teamPublished

Most yt-dlp “HTTP Error 403: Forbidden” errors are an outdated build or a missing JavaScript runtime — not a ban. Run yt-dlp -U, install Deno, retry with -4 --rm-cache-dir. If the 403 survives that, this guide maps each symptom to its real cause: forced formats, missing PO tokens, cookies that make things worse, and data-center IPs that YouTube refuses to serve media to.

The quick fix

yt-dlp -U                                   # or: pip install -U yt-dlp
curl -fsSL https://deno.land/install.sh | sh  # JS runtime for YouTube challenge solving
yt-dlp -4 --rm-cache-dir "https://youtu.be/dQw4w9WgXcQ"

Three commands fix the large majority of 403 reports. If yours is not among them, do not start throwing flags at it — work through the list below in order. Each step answers a different cause, and the wrong one (cookies, usually) can make a temporary 403 permanent.

What “HTTP Error 403: Forbidden” means in yt-dlp

A 403 is YouTube refusing to serve something it just offered. There are two very different places it can happen. The first is the info request (the watch page or player API): YouTube will not even tell yt-dlp which formats exist — that is a trust problem with your client or IP. The second, and far more common, is the media request: yt-dlp got a list of formats and a signed googlevideo.com URL, started downloading, and the media server answered 403. That URL was signed for a specific client, IP and Proof-of-Origin token; if any of those do not match what YouTube expected, the download is refused even though the metadata looked fine.

Knowing which of the two you have decides the fix. Run with -v: if the error appears after “Downloading … formats” or mid-download, it is a media 403 (steps 4 to 7 below); if it appears before any format is listed, it is an info 403 (steps 1 to 3, then the bot-wall guide).

Fix yt-dlp 403 in this order

1. Update yt-dlp

YouTube ships changes to how media URLs are signed and served every few weeks, specifically to break automated clients, and yt-dlp answers within days. Any build older than a month can produce 403s that no flag will fix. Use the official binary or pip — distribution packages are often months behind — and consider the nightly channel if a stable release is not out yet.

2. Install a JavaScript runtime (Deno)

Since 2025 yt-dlp needs an external JS runtime to solve YouTube’s signature and challenge code. Without one it silently loses formats or falls back to a delivery method that 403s. Deno is the recommended runtime; Node.js and Bun are supported. Install it and check that yt-dlp -v lists it in the debug header. If you had the old YTNsigDeno plugin installed, remove it — it is obsolete and conflicts with the built-in solver.

3. Clear the cache and force IPv4

yt-dlp -4 --rm-cache-dir "https://youtu.be/dQw4w9WgXcQ"

A stale signature cache from a previous version produces 403s on every video; --rm-cache-dir resets it. -4 matters on servers with IPv6: YouTube scores a whole IPv6 /64 as one address, and on our own fleet in August 2026 roughly three in ten extractions returned a media host that refused IPv6 but served the same URL fine over IPv4.

4. Stop forcing a specific format

Since August 2026 a wave of reports show 403s when a format is forced with -f (for example -f 137+140) while automatic selection succeeds. YouTube now serves some itags only to clients that hold a PO token, and a forced itag ignores that. Drop the -f, or express your preference with sorting instead:

# prefer 1080p mp4 without forcing a specific itag
yt-dlp -S "res:1080,ext:mp4" "https://youtu.be/dQw4w9WgXcQ"

5. Try a different player client

yt-dlp --extractor-args "youtube:player_client=android" "https://youtu.be/dQw4w9WgXcQ"
# also: tv, mweb, web_embedded — each is signed and trusted differently

YouTube signs media URLs per client, and the set of clients that get untainted URLs changes often. Switching client is a legitimate workaround, not a permanent fix; some clients cap at 720p or need their own cookies. Watch the -v output for “requires a PO token” — that message points to step 6, not to more client hopping.

6. Provide a PO token

Some formats and clients are only served with a Proof-of-Origin token minted by YouTube’s BotGuard script. With a JS runtime yt-dlp can mint one for some clients; for the rest install a provider plugin (bgutil-ytdlp-pot-provider), which runs a small token service yt-dlp calls automatically. The classic sign of a missing token is a media 403 on 1080p+ while 360p works.

7. Cookies — carefully, and not as the first move

Cookies solve the info 403 (“Sign in to confirm you’re not a bot”), but they can create media 403s: the maintainers note that some formats become unavailable when cookies are passed, and a cookie jar exported from a browser that is still open gets invalidated when the browser rotates the session. If you need them, export from a private window logged into a spare account, close the window, then pass --cookies cookies.txt. Never use your main account on a server.

8. Back off and change the IP

yt-dlp --sleep-requests 2 --sleep-interval 5 --max-sleep-interval 15 --limit-rate 2M ...

Bulk runs get rate-limited into 403s; add sleeps and cap concurrency. If a clean laptop on a home connection downloads the same video while the server cannot, the server’s IP reputation is the cause — route through a residential proxy (--proxy) or move the extraction elsewhere. Cheap data-center proxies score like your VPS and rarely help.

Symptom → cause

  • 403 before any format is listed → info-level refusal: update (1), JS runtime (2), then the bot-wall guide.
  • 403 immediately on every video after it worked yesterday → YouTube changed something: update (1), clear cache (3).
  • First chunk downloads, then 403 → the signed URL does not match the client/IP/token that requested it; do not trust a successful first chunk. Try another client (5), PO token (6).
  • 403 only for 1080p and above, 360p works → PO-token-gated formats (6) or a forced itag (4).
  • Works on a laptop, 403 on the VPS → IP reputation and/or IPv6 (3, then 8).
  • 403 only during playlists or bulk runs → rate limiting (8).
  • Started failing right after adding cookies → cookies are the cause (7): remove them or re-export from a closed private window.

Why servers and IPv6 get 403 more often

YouTube treats data-center ranges (AWS, GCP, Azure, every VPS provider) as likely automation and serves them fewer formats, more challenges and more refusals. Two figures from our own extraction fleet, measured in August 2026: about one in four fresh exit IPs hit a challenge on first contact, and about three in ten extractions returned a googlevideo host that was unreachable or refused over IPv6 while working over IPv4. That is why the same command succeeds on a laptop and fails on a server — and why -4 is worth trying before anything else.

Common mistakes

  • Passing cookies to every client, including ones that must not use them — yt-dlp warns about this; heed the warning.
  • Running as root with a shared, stale cache; use --rm-cache-dir and per-user config.
  • Forcing itags copied from an old tutorial (-f 137+140) instead of sorting with -S.
  • Retrying in a tight loop after a 403, which converts a temporary refusal into a flagged IP.
  • Still running a distro package from last year and reading forum threads instead of updating.

When patching stops paying off

If yt-dlp is inside a bot, an app or a pipeline, the 403 dance — updates, runtimes, PO tokens, cookie hygiene, clean IPs — is a recurring operations cost. A hosted API keeps all of it server-side and returns a download URL in one request:

curl "https://tunelio.dev/create?url=https://youtu.be/dQw4w9WgXcQ&quality=1080p" \
  -H "Authorization: Bearer tnl_your_api_key"
# → { "url": "https://…/tunnel?id=…&sig=…", "file_size_str": "58.11 MB", "status": "ok" }

Tunelio is our own service, so read this section with that in mind. For occasional downloads from a home connection, steps 1 to 3 will carry you and yt-dlp stays the right tool. For anything that runs unattended on a server, it is usually cheaper to stop owning the problem. New accounts get 100 free credits, no card required.

Sources and further reading

  • yt-dlp issue #14680 — “FIXED: [Youtube] ERROR: unable to download video data: HTTP Error 403: Forbidden”.
  • yt-dlp issue #17395 — intermittent 403 when downloading videos (open tracking issue).
  • yt-dlp README — JavaScript runtime requirement (Deno recommended) and the extractor-args reference.
  • yt-dlp wiki — PO token guide and “How do I pass cookies to yt-dlp?”.
  • Our own measurements (Tunelio extraction fleet, August 2026): IPv6 media-host refusals and first-contact challenge rates.

Frequently asked questions

Do cookies fix a 403?

They fix the login-wall kind of refusal, not the media kind. Cookies can even cause media 403s by making some formats unavailable or by expiring when the browser rotates the session. Use them last, from a closed private window.

Is 403 caused by my IP?

Often on servers: data-center and IPv6 addresses are scored as likely bots. If a laptop on a home connection succeeds with the same command, the IP is the cause — try -4 first, then a residential exit.

Why did it break overnight?

YouTube changed its player or signing code and your yt-dlp is now out of date. Update, clear the cache with --rm-cache-dir, and make sure a JavaScript runtime is installed.

The first part downloads and then it 403s — what is that?

The signed media URL did not match the client, IP or PO token YouTube expected; the first chunk is not proof the URL is valid. Switch client, provide a PO token, and avoid forcing itags.

Related guides