ytdl-org/youtube-dl · error · ExtractorError

Udemy asks you to solve a CAPTCHA. Login with browser, solve

Error message

Udemy asks you to solve a CAPTCHA. Login with browser, solve CAPTCHA, then export cookies and pass cookie file to youtube-dl with --cookies.

What it means

Raised by UdemyIE._download_webpage_handle when the fetched page contains PerimeterX bot-protection markers ('Please verify you are a human', the automation-tools denial text, or the _pxCaptcha field). It tells the user to solve the CAPTCHA in a browser and reuse the session cookies. Expected error.

Source

Thrown at youtube_dl/extractor/udemy.py:143

            error_data = error.get('data')
            if error_data:
                error_str += ' - %s' % error_data.get('formErrors')
            raise ExtractorError(error_str, expected=True)

    def _download_webpage_handle(self, *args, **kwargs):
        headers = kwargs.get('headers', {}).copy()
        headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
        kwargs['headers'] = headers
        ret = super(UdemyIE, self)._download_webpage_handle(
            *args, **compat_kwargs(kwargs))
        if not ret:
            return ret
        webpage, _ = ret
        if any(p in webpage for p in (
                '>Please verify you are a human',
                'Access to this page has been denied because we believe you are using automation tools to browse the website',
                '"_pxCaptcha"')):
            raise ExtractorError(
                'Udemy asks you to solve a CAPTCHA. Login with browser, '
                'solve CAPTCHA, then export cookies and pass cookie file to '
                'youtube-dl with --cookies.', expected=True)
        return ret

    def _download_json(self, url_or_request, *args, **kwargs):
        headers = {
            'X-Udemy-Snail-Case': 'true',
            'X-Requested-With': 'XMLHttpRequest',
        }
        for cookie in self._downloader.cookiejar:
            if cookie.name == 'client_id':
                headers['X-Udemy-Client-Id'] = cookie.value
            elif cookie.name == 'access_token':
                headers['X-Udemy-Bearer-Token'] = cookie.value
                headers['X-Udemy-Authorization'] = 'Bearer %s' % cookie.value

        if isinstance(url_or_request, compat_urllib_request.Request):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Log into Udemy in a normal browser, solve any CAPTCHA, export cookies, and pass --cookies udemy_cookies.txt.
  2. Slow down: add --sleep-interval/--max-sleep-interval and limit parallelism (--limit-rate, fewer concurrent jobs).
  3. Run from a residential IP rather than a datacenter/VPN egress.
  4. Retry later; PerimeterX blocks are often temporary once a clean session is established.
Defensive patterns

Strategy: fallback

Type guard

def px_blocked(page: str) -> bool:
    return any(m in page for m in ('Please verify you are a human', '_pxCaptcha', 'automation tools'))

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'CAPTCHA' in str(e):
        pause_and_switch_to_fresh_cookies()  # solve in browser, re-export, resume
    else:
        raise

Prevention

When it happens

Trigger: Any Udemy webpage download whose HTML contains one of the three PerimeterX markers — triggered by datacenter IPs, high request rates, a spoofed Chrome 72 User-Agent the site distrusts, or missing valid cookies.

Common situations: Batch-download scripts hammering udemy.com, running from cloud/VPN IPs, expired cookie jars, repeated login attempts.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/b3a9d650eaba4112. Report an issue: GitHub.