{"record":{"id":"2614aa27c1695d9e","repo":"yt-dlp/yt-dlp","slug":"unable-to-extract-embedurl","errorCode":null,"errorMessage":"Unable to extract embedUrl","messagePattern":"Unable to extract embedUrl","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/ndr.py","lineNumber":136,"sourceCode":"                default=None)\n            or self._search_regex(\n                r'\\bembedUrl[\"\\']\\s*:\\s*([\"\\'])(?P<url>(?:(?!\\1).)+)\\1', webpage,\n                'embed URL', group='url', default=None)\n            or self._search_regex(\n                r'\\bvar\\s*sophoraID\\s*=\\s*([\"\\'])(?P<url>(?:(?!\\1).)+)\\1', webpage,\n                'embed URL', group='url', default=''))\n        # some more work needed if we only found sophoraID\n        if re.match(r'^[a-z]+\\d+$', embed_url):\n            # get the initial part of the url path,. eg /panorama/archiv/2022/\n            parsed_url = urllib.parse.urlparse(url)\n            path = self._search_regex(rf'(.+/){display_id}', parsed_url.path or '', 'embed URL', default='')\n            # find tell-tale image with the actual ID\n            ndr_id = self._search_regex(rf'{path}([a-z]+\\d+)(?!\\.)\\b', webpage, 'embed URL', default=None)\n            # or try to use special knowledge!\n            NDR_INFO_URL_TPL = 'https://www.ndr.de/info/%s-player.html'\n            embed_url = f'ndr:{ndr_id}' if ndr_id else NDR_INFO_URL_TPL % (embed_url, )\n        if not embed_url:\n            raise ExtractorError('Unable to extract embedUrl')\n\n        description = self._search_regex(\n            r'<p[^>]+itemprop=\"description\">([^<]+)</p>',\n            webpage, 'description', default=None) or self._og_search_description(webpage)\n        timestamp = parse_iso8601(\n            self._search_regex(\n                (r'<span[^>]+itemprop=\"(?:datePublished|uploadDate)\"[^>]+content=\"(?P<cont>[^\"]+)\"',\n                 r'\\bvar\\s*pdt\\s*=\\s*(?P<q>[\"\\'])(?P<cont>(?:(?!(?P=q)).)+)(?P=q)'),\n                webpage, 'upload date', group='cont', default=None))\n        info = self._search_json_ld(webpage, display_id, default={})\n        return merge_dicts({\n            '_type': 'url_transparent',\n            'url': embed_url,\n            'display_id': display_id,\n            'description': description,\n            'timestamp': timestamp,\n        }, info)\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/ndr.py#L118-L154","documentation":"Thrown by NDRIE._real_extract (yt_dlp/extractor/ndr.py:136). NDR articles expose media via a direct embed URL, a 'sophora ID' short code (pattern ^[a-z]+\\d+$) that triggers a secondary page-path/image scan, or the NDR info-player template; when embed_url is still falsy after all of those fallbacks, extraction stops.","triggerScenarios":"An ndr.de/sportschau article page where the embed-URL regex, the path+image-based sophora-ID lookup, and the info-player fallback all fail: text-only article, JS-rendered player, or a template change that moved the media references.","commonSituations":"Article links that contain no A/V media at all; NDR redesigns (happened repeatedly - the layered fallbacks in this function are scar tissue); audio items handled by a sibling extractor; JS-only pages served to bots.","solutions":["Confirm in a browser that the article actually contains playable video or audio","Update yt-dlp to latest nightly - NDR markup changes are common and patched","Try the canonical /mediathek/ or ndr: <doc-id> form of the same content","Open devtools, find the real iframe/video src on the page, and pass that URL directly","Report with --verbose if the page has media but extraction still fails"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import re, urllib.request\n\ndef ndr_page_has_media(url) -> bool:\n    with urllib.request.urlopen(urllib.request.Request(url, headers={'User-Agent': UA})) as r:\n        html = r.read().decode('utf-8', 'replace')\n    return bool(re.search(r'(data-url=|embed|mediathek|<iframe)', html))","typeGuard":null,"tryCatchPattern":"from yt_dlp.utils import ExtractorError\ntry:\n    info = ydl.extract_info(url, download=False)\nexcept ExtractorError as e:\n    if 'Unable to extract embedUrl' in str(e):\n        # all fallbacks failed: likely text-only article or markup change\n        skip_article(url)","preventionTips":["Filter out NDR article URLs with no media before queuing (text-only articles are common)","Keep yt-dlp updated; NDR markup changes break embed discovery regularly","Store the canonical /mediathek/ or ndr: doc-id form when you first resolve a video"],"tags":["yt-dlp","extractor","ndr","webpage-parsing","embed-url"],"backgroundTag":"embed-url-not-found","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}