yt-dlp/yt-dlp · error · ExtractorError
Unable to extract embedUrl
Error message
Unable to extract embedUrl
What it means
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.
Source
Thrown at yt_dlp/extractor/ndr.py:136
default=None)
or self._search_regex(
r'\bembedUrl["\']\s*:\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
'embed URL', group='url', default=None)
or self._search_regex(
r'\bvar\s*sophoraID\s*=\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
'embed URL', group='url', default=''))
# some more work needed if we only found sophoraID
if re.match(r'^[a-z]+\d+$', embed_url):
# get the initial part of the url path,. eg /panorama/archiv/2022/
parsed_url = urllib.parse.urlparse(url)
path = self._search_regex(rf'(.+/){display_id}', parsed_url.path or '', 'embed URL', default='')
# find tell-tale image with the actual ID
ndr_id = self._search_regex(rf'{path}([a-z]+\d+)(?!\.)\b', webpage, 'embed URL', default=None)
# or try to use special knowledge!
NDR_INFO_URL_TPL = 'https://www.ndr.de/info/%s-player.html'
embed_url = f'ndr:{ndr_id}' if ndr_id else NDR_INFO_URL_TPL % (embed_url, )
if not embed_url:
raise ExtractorError('Unable to extract embedUrl')
description = self._search_regex(
r'<p[^>]+itemprop="description">([^<]+)</p>',
webpage, 'description', default=None) or self._og_search_description(webpage)
timestamp = parse_iso8601(
self._search_regex(
(r'<span[^>]+itemprop="(?:datePublished|uploadDate)"[^>]+content="(?P<cont>[^"]+)"',
r'\bvar\s*pdt\s*=\s*(?P<q>["\'])(?P<cont>(?:(?!(?P=q)).)+)(?P=q)'),
webpage, 'upload date', group='cont', default=None))
info = self._search_json_ld(webpage, display_id, default={})
return merge_dicts({
'_type': 'url_transparent',
'url': embed_url,
'display_id': display_id,
'description': description,
'timestamp': timestamp,
}, info)
View on GitHub (pinned to 81ecd58b13)
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
Defensive patterns
Strategy: try-catch
Validate before calling
import re, urllib.request
def ndr_page_has_media(url) -> bool:
with urllib.request.urlopen(urllib.request.Request(url, headers={'User-Agent': UA})) as r:
html = r.read().decode('utf-8', 'replace')
return bool(re.search(r'(data-url=|embed|mediathek|<iframe)', html)) Try / catch
from yt_dlp.utils import ExtractorError
try:
info = ydl.extract_info(url, download=False)
except ExtractorError as e:
if 'Unable to extract embedUrl' in str(e):
# all fallbacks failed: likely text-only article or markup change
skip_article(url) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- No video metadata found in webpage
- No playlist or embed found in webpage
- Unsafe placeholder for exec command: {na!r} The --output-na-
- Unsafe default(s) in exec command: {outtmpl!r} Conversions a
- Invalid syntax in Cookie Header
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/2614aa27c1695d9e.
Report an issue: GitHub.