You update a docs page, move a file, rename a heading. Nothing breaks loudly. A reader clicks a link weeks later and lands on a 404 — or worse, on the right page with the wrong anchor, staring at the top while the section they wanted is three screens down.
Most link checkers give you one word: broken. This one tells you which kind of broken, because the fix is different.
broken-link-checker-cli is a Python CLI. Standard library only. It scans .md, .markdown and .html files, checks every link for real, and reports each link as one of three things:
-
OK— the page exists, and the anchor on it exists too. -
BROKEN (page)— the page itself is missing. -
BROKEN (anchor)— the page exists, the anchor on it does not.
A link is never reported OK unless its check actually ran. If an anchor cannot be checked (a PDF, for example), the link is reported SKIPPED with the reason — never silently OK. Links inside fenced code blocks and inline code are ignored, so code samples never produce false failures. mailto: and tel: links are skipped, not flagged.
Try it
pip install broken-link-checker-cli Point it at your docs folder:
broken-link-checker docs/ The repo ships with an examples/ folder you can try first — one link in there is deliberately broken:
git clone https://github.com/haiderstudio/broken-link-checker-cli.git cd broken-link-checker-cli broken-link-checker examples/ Real output:
examples/sample-docs.md:3: other-page.md -> OK examples/sample-docs.md:5: #sample-docs -> OK examples/sample-docs.md:8: missing-page.md -> BROKEN (page) (file does not exist) 2 ok, 1 broken, 0 skipped Remote links are checked with HEAD, falling back to GET where a server refuses HEAD. If a remote link has an anchor, the fetched page must carry that id or name.
Useful flags
# Local files only — works fully offline broken-link-checker --local-only docs/ # Machine-readable output for CI broken-link-checker --format json docs/ # Skip URLs matching a pattern (repeatable) broken-link-checker --exclude 'example\.com' docs/ Exit code 0 means no broken links, 1 means at least one broken link, 2 means a usage error such as a missing path — so it drops straight into CI as a gate.
What it does not do
It does not rewrite any file, follow JavaScript-rendered pages, or log in anywhere. It only reads and reports. It does not send your docs anywhere — remote checks are plain requests to the linked URL itself.
I built it because every docs check I tried either needed a service, a Node install, or reported "broken" without saying which part was broken. This one is one file, stdlib only, and the output tells you exactly what to fix.
The repo is MIT licensed: https://github.com/haiderstudio/broken-link-checker-cli
If it catches a broken link in your docs, a star helps other people find it.