Markdown link checker
Updated
Paste a README or any markdown document and get every link listed with its line number — then check the external ones for dead pages and redirects, catch #anchors that no heading produces, and spot duplicate or undefined reference links before you publish.
| Line | Kind | Text | URL | Result |
|---|---|---|---|---|
| 3 | link | installation guide | #installation | anchor found |
| 3 | link | API reference | #api-reference | anchor missing no heading produces #api-reference |
| 7 | link | GitHub | https://github.com/vercel/next.js | pending |
| 8 | link | docs | https://nextjs.org/docs | pending |
| 9 | autolink | https://example.com/this-page-does-not-exist-404 | https://example.com/this-page-does-not-exist-404 | pending |
| 11 | bare URL | http://github.com/vercel/next.js | http://github.com/vercel/next.js | pending |
| 15 | link | config.md | ./docs/config.md#options | relative — can't check from here |
| 15 | autolink | mailto:team@example.com | mailto:team@example.com | not checked |
| 17 | reference | changelog | https://github.com/vercel/next.js/releases | pending |
| 17 | reference | roadmap | — | undefined reference no [roadmap]: url line |
| 19 | image | Architecture | ./images/architecture.png | relative — can't check from here |
| 21 | link | Next.js docs | https://nextjs.org/docs | pendingduplicate |
Parsing and anchor checks run in your browser. Only the external http(s) URLs are sent to docs-md.com's server, which fetches them on your behalf — your document text is never uploaded. Relative paths and mailto links are listed but not fetched.
Which kinds of links does the checker find?
All six ways a URL can appear in markdown: inline links [text](url), images , reference-style links [text][id] together with their [id]: url definitions, autolinks in angle brackets, bare URLs that GitHub turns into links automatically, and HTML <a href> or <img src> tags. Anything inside a fenced code block or inline backticks is ignored, since it is not rendered as a link.
What does each result mean?
- 2xx, green — the page answered. 3xx, amber — it redirects; the final address is shown so you can update the link.
- 4xx / 5xx, red — the page is missing, forbidden, or the server failed. 404 is a genuinely dead link; 403 often means the site blocks link checkers (see the FAQ).
- Anchor missing — a
#sluglink that no heading in the document produces. The table of contents generator builds correct anchors from your headings. - Undefined reference —
[text][id]with no[id]: urlline, which renders as literal brackets. The link generator writes reference links with matching definitions. - Duplicate — the same URL appears more than once; fine in prose, but in a link list it usually means a copy-paste slip.
How do I keep links from breaking in the first place?
Prefer permanent URLs (release pages, tagged docs) over “latest” links, link to headings by their generated slug rather than a guessed one, and keep reference definitions at the bottom of the file where they are easy to audit. Run the check again after editing: every problem row is clickable and selects the offending line in the editor. For a repository, add a link checker to CI as well — this page is for the quick pass before you commit.
What is sent to the server when I check links?
Only the list of external http(s) URLs. Parsing, anchor verification, duplicate detection, and reference checks all run in your browser; the markdown text itself never leaves your machine. The server fetches each URL once (HEAD, then GET if needed) and returns the status code.
Why does a link that works in my browser show 403 or an error here?
Some sites (Cloudflare-protected pages, LinkedIn, some publishers) block automated requests or answer HEAD requests with 403 or 405. The checker retries with GET, but a site that refuses non-browser traffic will still report an error. Treat a 403 on a page you know is public as "blocked by the site", not as a dead link.
How are #anchor links verified?
The checker builds the same heading slugs GitHub does (via github-slugger): lowercase, spaces to hyphens, punctuation dropped, and -1, -2 suffixes on duplicates. A link like #getting-started passes when a heading produces that slug, or when an explicit HTML id or name attribute defines it.
Why are relative links like ./docs/setup.md not checked?
The tool only sees the one document you pasted, so it cannot know whether a sibling file exists in your repository. Relative links are listed with their line numbers so you can verify them where the files live; anchors within the same document are checked.
Does a redirect count as broken?
No. A 301 or 302 is shown in amber with the final URL so you can decide whether to update the link. Permanent redirects are worth fixing in a README because each hop adds latency and some renderers refuse to follow them.
Is there a limit on how many links I can check?
Up to 100 unique external URLs per run, checked in batches of 25 with an 8-second timeout each, and 20 runs per 10 minutes per IP address. That covers a long README comfortably.