Guides · Updated 2026-10-25
yt-dlp Instagram "Login Required" Error on a Server
The script works on your laptop. You deploy it to a VPS, a Lambda or a Docker container, and Instagram downloads start failing with something like:
ERROR: [Instagram] DcTa7nogl9z: Requested content is not available, rate-limit reached or login required. Use --cookies, --cookies-from-browser, --username and --password, --netrc-cmd, or --netrc (instagram) to provide account credentialsinstaloader users see the same thing in a different form: 401 Unauthorized with "Please wait a few minutes before you try again". It's rarely a bug in either tool.
Why it happens
- Your IP is a datacenter IP. Instagram treats logged-out traffic from cloud providers far more strictly than traffic from home and mobile connections. The same command that works at home gets a login wall from AWS, GCP, Hetzner or DigitalOcean.
- Rate limits are per IP and tight. A batch job that fetches a few dozen posts in a row trips them even from a good IP.
- Instagram changes its web responses often. An old yt-dlp version can fail on content that a current one handles.
Fixes, roughly in order of effort
1. Update yt-dlp. Rule this out first:
yt-dlp -U # standalone binary
pip install -U yt-dlp # pip install2. Slow down. Space out requests so a batch doesn't look like a burst:
yt-dlp --sleep-requests 2 --sleep-interval 5 --max-sleep-interval 15 -a urls.txt3. Pass cookies from a logged-in account. This is the fix yt-dlp suggests, and it works:
# on a machine with a browser where you're logged in
yt-dlp --cookies-from-browser firefox --cookies cookies.txt --skip-download "https://www.instagram.com/reel/DcTa7nogl9z/"
# copy cookies.txt to the server
yt-dlp --cookies cookies.txt "https://www.instagram.com/reel/DcTa7nogl9z/"The catch: the session is now tied to an Instagram account making automated requests from a server. Expect checkpoints ("confirm it's you"), expired cookies you have to refresh by hand, and on heavier use a suspended account. Never use your personal account for this.
4. Route through a residential proxy. --proxy http://user:pass@host:port with a residential or mobile IP gets you past the datacenter penalty. It works, but the proxy bill is per GB, video is heavy, and you still need step 1 and 2.
5. Hand the problem off. If downloading is a feature of your product rather than the product itself, a hosted API that resolves the URL for you removes the cookies, proxies and version chasing from your server.
Trade-offs
| Approach | Works from a VPS | Needs an Instagram account | Ongoing upkeep |
|---|---|---|---|
| yt-dlp, logged out | Often blocked | No | Frequent updates |
| yt-dlp + cookies | Usually, until the session is flagged | Yes, and it can get banned | Refresh cookies, replace accounts |
| yt-dlp + residential proxy | Mostly | No | Proxy cost per GB, updates |
| Hosted API (soclip) | Yes | No | None on your side; $0.002 per lookup |
Swapping yt-dlp for an API call
If you were calling yt-dlp to get a direct URL (yt-dlp -g) or the file, this is the equivalent:
curl -s -X POST https://api.soclip.dev/v1/media \
-H "Authorization: Bearer $SOCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.instagram.com/reel/DcTa7nogl9z/"}' \
| jq -r '.data.medias[0].url' \
| xargs -I{} curl -sL -o reel.mp4 "{}"It handles Instagram, TikTok, X/Twitter and Facebook. It doesn't do YouTube — for YouTube, yt-dlp is still the tool. Sign in with GitHub at soclip.dev for 500 free credits (250 lookups); failed lookups aren't charged. Code for Python and Node.js.