· 4 min read
How to Find Anchor Links That Go Nowhere
Manesh Jayawardhana
CIO & Co-founder
A reader clicks “Pricing” in the table of contents and nothing happens. Not an error page, not a scroll to the wrong place — nothing at all.
The heading was renamed from “Pricing” to “Pricing and plans” eight months ago, its generated id changed with it, and the link has pointed at nothing ever since. No monitoring caught it because the page returns 200 and the link is not to another page.
Why these break silently
A fragment link points at an id within the current page. If no element has that id, the browser does nothing — no navigation, no console error, no network request.
That silence is why they accumulate:
Link checkers do not catch them. A crawler checks that URLs resolve. /guide#setup resolves to /guide, which returns 200, and the fragment is never evaluated.
Analytics do not catch them. No page view, no event, no signal.
Nobody reports them. A reader clicks, nothing happens, they scroll to find it manually and move on. It reads as a slightly clunky page rather than a bug.
Renamed headings are the main cause
Most systems generate heading ids from the heading text — “Pricing and plans” becomes pricing-and-plans. Change the wording and the id changes.
Every link pointing at the old id breaks at that moment. On a page with a generated table of contents this fixes itself, because the contents regenerate. On a page with hand-written internal links, or links from other pages, it does not.
The other causes are consistent: a section removed but still linked from elsewhere, a typo when the link was written, and a heading whose generated id differs from what someone assumed — punctuation and capitalisation both affect it.
| Cause | Where it shows |
|---|---|
| Heading renamed | Hand-written links, cross-page links |
| Section deleted | Everywhere linking to it |
| Typo in the fragment | One link |
| Assumed id differs from generated | Links written by hand |
Duplicate ids are the other half
An id must be unique within a document. Two elements sharing one is invalid HTML with practical consequences.
A browser jumps to the first match, so the second element is unreachable by link. Assistive technology behaviour with duplicate ids is inconsistent, and aria-labelledby or aria-describedby pointing at a duplicated id resolves to whichever comes first, which may not be the intended label.
Duplicates usually come from two headings with the same text — “Overview” appearing in three sections — or a component rendered twice on one page with a hard-coded id.
Set explicit ids on anything you link to
The durable fix rather than the repeated repair.
Most systems generate heading ids from heading text, which means the id changes whenever the wording does. Every hand-written link and every cross-page link pointing at it breaks silently at that moment.
Setting an explicit id decouples them. The heading can be rewritten freely and the id — and every link to it — survives.
Most markdown processors and CMS platforms support explicit heading ids through an attribute syntax or a front-matter field. Where they do not, an empty anchor element immediately before the heading achieves the same thing.
It is worth doing for any heading linked from another page, which is a much smaller set than every heading.
Common mistakes to avoid
- Assuming a link checker covers fragments. It does not.
- Renaming headings without checking what links to them.
- Hard-coding ids in components that can appear more than once on a page.
- Checking the template source rather than the rendered HTML, where ids are actually generated.
- Fixing the link when the id was the thing that changed, so the next rename breaks it again.
How to do it with Broken Anchor Link Finder
The Broken Anchor Link Finder checks fragments against the ids that exist.
- Paste the rendered page HTML rather than the template source.
- Fix links pointing at ids that no longer exist — usually a renamed heading.
- Resolve duplicate ids, since the second occurrence is unreachable.
- Consider adding explicit ids to headings so future renames do not break links.
Other SEO tools are in the tools directory.
Frequently asked questions
Why do link checkers miss these?
Because the URL resolves. /guide#setup fetches /guide, which returns 200, and the fragment is never evaluated against the page content.
What breaks anchor links most often?
Renaming a heading, when ids are generated from heading text. The link keeps the old fragment, the id becomes something else, and nothing reports it.
Do duplicate ids matter?
Yes. Browsers jump to the first match, making the second element unreachable by link, and assistive technology behaviour becomes unpredictable — particularly for aria attributes pointing at a duplicated id.
Final thought
Set explicit ids on headings you link to. Generated ids follow the wording, and wording changes.