# Extension points — ytdl-org/youtube-dl

> Canonical page: https://codevetter.com/unpack/youtube-dl/extension-points

# Extension points — ytdl-org/youtube-dl

Scanned commit 956b8c585591b401a543e409accb163eeaaa1193 (2025-11-26). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The codebase is explicitly designed around plugin points. Primary: site extractors subclass InfoExtractor, define _VALID_URL + _real_extract, embed _TEST dicts, and register via an import line in extractor/extractors.py (plus optional lazy_extractors generation). Secondary: downloaders plug into PROTOCOL_MAP or the external-downloader _BY_NAME registry, postprocessors resolve by the '<key>PP' naming convention, and embedders hook progress_hooks, match_filter, custom logger, and the postprocessors param list.
- New site support follows a documented recipe: create youtube_dl/extractor/<name>.py with an InfoExtractor subclass (class name ending in IE), define _VALID_URL regex and _real_extract, add a _TEST dict, and add one import line to extractor/extractors.py. — [CONTRIBUTING.md#L99-166](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/CONTRIBUTING.md#L99-L166) [youtube_dl/extractor/common.py#L383-417](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L383-L417) [youtube_dl/extractor/extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/extractors.py)
- Extractor ordering is semantic: gen_extractor_classes returns _ALL_CLASSES in import order and the first suitable() match wins; GenericIE is appended last as the catch-all, so new extractors must be added before it implicitly by import placement. — [youtube_dl/extractor/__init__.py#L11-30](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L11-L30) [youtube_dl/YoutubeDL.py#L866-875](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L866-L875)
- Lazy loading is a compile-time extension artifact: devscripts/make_lazy_extractors.py generates youtube_dl/extractor/lazy_extractors.py from _ALL_CLASSES; this constrains extractor authors — overridden suitable() must import its own dependencies and avoid _VALID_URL references (documented in InfoExtractor's docstring). — [devscripts/make_lazy_extractors.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/devscripts/make_lazy_extractors.py) [youtube_dl/extractor/common.py#L391-395](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L391-L395) [youtube_dl/extractor/__init__.py#L3-8](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/__init__.py#L3-L8) [Makefile#L114-118](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/Makefile#L114-L118)
- SearchInfoExtractor is the extension base for 'keyword' providers (e.g. ytsearch): subclasses set _SEARCH_KEY and implement _real_extract over a query string, producing a playlist of url_results. — [youtube_dl/extractor/common.py#L3365-3406](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L3365-L3406)
- url_result()/playlist_result() are the delegation mechanism: an extractor can emit _type 'url' entries with an ie_key to hand a URL off to another extractor, enabling composite extractors without subclassing. — [youtube_dl/extractor/common.py#L365-381](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L365-L381) [youtube_dl/extractor/common.py#L1031-1061](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L1031-L1061) [youtube_dl/YoutubeDL.py#L1009-1019](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1009-L1019)
- New downloaders subclass FileDownloader and implement real_download(filename, info_dict); protocol-based selection goes through PROTOCOL_MAP in downloader/__init__.py, while external-executable downloaders subclass ExternalFD (_make_cmd) and self-register in _BY_NAME keyed by executable basename. — [youtube_dl/downloader/common.py#L396-398](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/common.py#L396-L398) [youtube_dl/downloader/__init__.py#L29-39](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/__init__.py#L29-L39) [youtube_dl/downloader/external.py#L85-138](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L85-L138) [youtube_dl/downloader/external.py#L520-536](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/external.py#L520-L536)
- New postprocessors subclass PostProcessor with a run(info)->(files_to_delete, info) contract; registration is by naming convention — a param dict {'key': 'X'} resolves to class XPP via get_postprocessor, and the CLI assembles the list in __init__. — [youtube_dl/postprocessor/common.py](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/common.py) [youtube_dl/postprocessor/__init__.py#L21-22](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/postprocessor/__init__.py#L21-L22) [youtube_dl/__init__.py#L253-308](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/__init__.py#L253-L308) [youtube_dl/YoutubeDL.py#L463-468](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L463-L468)
- Library/embedding hooks: YoutubeDL accepts progress_hooks (status dicts with downloading/error/finished and byte/eta/speed fields), a logger object, match_filter callable, extract_flat mode, and a postprocessors list — the documented embedding API. — [youtube_dl/YoutubeDL.py#L267-290](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L267-L290) [youtube_dl/YoutubeDL.py#L313-317](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L313-L317) [youtube_dl/YoutubeDL.py#L522-525](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L522-L525) [README.md#L1444](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/README.md#L1444)
- Per-request behaviors can be injected through info_dict fields read downstream: http_headers, downloader_options (http_chunk_size), fragments, protocol, stretched_ratio, __postprocessors and __files_to_merge — extractors/downstream code cooperate through these keys. — [youtube_dl/YoutubeDL.py#L2085-2095](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L2085-L2095) [youtube_dl/downloader/http.py#L48-50](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/downloader/http.py#L48-L50) [youtube_dl/extractor/common.py#L167-219](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L167-L219)
- Geo-bypass is itself an extension surface: extractors declare _GEO_COUNTRIES/_GEO_IP_BLOCKS/_GEO_BYPASS and _initialize_geo_bypass can be invoked mid-extraction with a context dict when restriction info is only known after the first response. — [youtube_dl/extractor/common.py#L400-413](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L400-L413) [youtube_dl/extractor/common.py#L480-567](https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L480-L567)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
