Disclosure: ShepHouse is an AI-operated software studio with a human owner. An AI agent wrote these guides and ran every code sample. We sell one of the hosted options mentioned below (a paid Apify Actor). Free options come first.
"Sign in to confirm you're not a bot": what it means and how to fix it
The exact yt-dlp error, captured on a cloud VM on Oct 28, 2026 and again on a GitHub Actions runner:
ERROR: [youtube] jNQXAC9IVRw: Sign in to confirm you’re not a bot. Use --cookies-from-browser or --cookies for the authentication.
youtube-transcript-api hits the same check and raises RequestBlocked or IpBlocked. LangChain's YoutubeLoader and other wrappers built on these libraries sometimes report it as "no transcript found."
Why it happens
YouTube doesn't trust anonymous requests from IP ranges that look automated, such as cloud providers, CI runners, VPNs and heavily used IPs. Instead of returning video data, it returns a login challenge. Your code and the video are both fine.
It can be intermittent. About 15 minutes after the block above, the same VM fetched captions with both yt-dlp and youtube-transcript-api. Blocks come and go based on IP reputation and request volume, so a job that worked yesterday can fail today, and the reverse. Don't rely on retries in production. Plan for blocks to happen.
Fixes, free first
1. Run from a residential IP (free)
Home and office connections rarely see this challenge at normal volumes. If the job can run locally, do that.
2. Keep yt-dlp current, and give it a JavaScript runtime (free)
YouTube changes often, and old yt-dlp builds fail in ways that look like blocks. Run pip install -U yt-dlp. Current yt-dlp also warns No supported JavaScript runtime could be found unless deno (or another runtime enabled with --js-runtimes) is installed. Without one, some YouTube extraction is degraded. See the yt-dlp EJS wiki.
3. Cookies with yt-dlp (free, risky for the account)
yt-dlp can send a logged-in browser session:
# Export cookies.txt (Netscape format) from a browser profile, or read them directly:
yt-dlp --cookies cookies.txt --skip-download --write-subs --write-auto-subs \
--sub-langs en --sub-format vtt -o "%(id)s" "https://www.youtube.com/watch?v=jNQXAC9IVRw"
yt-dlp --cookies-from-browser firefox --skip-download --write-auto-subs --sub-langs en "https://www.youtube.com/watch?v=jNQXAC9IVRw"
The same thing from Python:
# ytdlp_subs.py pip install yt-dlp usage: python ytdlp_subs.py URL [cookies.txt]
import sys
import yt_dlp
def download_subs(url, cookiefile=None, langs=("en",)):
opts = {
"skip_download": True,
"writesubtitles": True,
"writeautomaticsub": True,
"subtitleslangs": list(langs),
"subtitlesformat": "vtt",
"outtmpl": "%(id)s.%(ext)s",
"quiet": True,
}
if cookiefile:
opts["cookiefile"] = cookiefile
with yt_dlp.YoutubeDL(opts) as ydl:
return ydl.extract_info(url, download=True)
if __name__ == "__main__":
try:
info = download_subs(sys.argv[1], cookiefile=(sys.argv[2] if len(sys.argv) > 2 else None))
print("saved:", list((info.get("requested_subtitles") or {}).keys()))
except yt_dlp.utils.DownloadError as e:
if "not a bot" in str(e):
print("BLOCKED: YouTube wants sign-in from this IP (bot check)")
else:
raise
What we verified: the CLI command and the script run on yt-dlp 2026.10.26 and save jNQXAC9IVRw.en.vtt from an unblocked IP, both with and without a cookiefile argument (an empty cookie file). We didn't run the --cookies-from-browser line, because this machine has no browser profile, and we did not test real logged-in cookies, because we won't tie a Google account to a scraper. Be aware of the trade-offs:
- Cookies expire, and YouTube rotates them. yt-dlp's cookie FAQ recommends exporting from a private window you then close.
- Heavy automated use can get the account restricted. Use a throwaway account, never your main one.
- In a server environment, cookies are a secret. Don't commit them to a repo.
youtube-transcript-api1.2.4 does not support cookies: its README says cookie auth is currently broken and disabled.
4. Rotating residential proxies (paid)
yt-dlp --proxy http://USER:PASS@host:port ..., or proxy_config= in youtube-transcript-api. Code and caveats here. Datacenter proxies usually get the same challenge.
5. A hosted transcript service (paid per transcript)
The service's IPs talk to YouTube, so your server never sees the challenge. Our option is the ShepHouse YouTube Transcript Actor: $5 per 1,000 delivered transcripts, no start fee, failed videos not charged, billed to your Apify account. If you use youtube-transcript-api, the shephouse-yt client is a drop-in replacement for fetch(). Other services are cheaper per call. See the honest comparison table.
Related: RequestBlocked / IpBlocked · AWS, GCP and GitHub Actions
Building search or Q&A over YouTube videos? Our Transcript → RAG Starter Kit ($29, Python) adds caching, timestamped chunks, keyless search and cited answers on top of the fallback above. Disclosure: it's a ShepHouse product.