How do you find broken internal links?
Crawl the site rendering JavaScript and including images and PDFs, and take the list of linking pages rather than the broken destinations — the sources are the actionable part. Then check what a crawl misses: orphaned pages, links inside PDFs, content that only renders on interaction, and email templates.
Crawl the site properly
A crawler follows every link from your homepage outward and records the status of each destination. That is the primary tool, and nothing else substitutes for it.
Set it up so it catches what matters:
- Render JavaScript if your navigation or content depends on it
- Include images, CSS, JavaScript and PDFs, not just HTML pages
- Follow both internal and external links, reporting separately
- Crawl the live site, not staging
What you want out of it is a list of broken destinations, each with the pages that link to them. The source list is the actionable part — the destination is just the symptom.
Check the places a crawl misses
A crawler only follows links it can find. Several categories escape it:
Orphaned pages. Nothing links to them, so nothing leads the crawler there. Compare a crawl against your sitemap and your CMS page list.
Links behind forms or logins. Anything requiring a session.
Links inside PDFs. Price lists and brochures often link to pages that have moved.
Links only rendered on interaction. Content inside tabs or accordions that loads on demand.
Email templates. Not on the site at all, but broken links there cost more than most on-site ones.
Read the server logs
Access logs show real 404s as they happen, including requests a crawl would never make — mistyped URLs, links from other sites, old bookmarks:
grep ' 404 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -30
Add the referrer field to that and you can tell whether the broken link is on your site or someone else's. If it is on someone else's and points at a page you removed, a redirect recovers the visitor.
Check Search Console too
The not-found reporting there shows URLs a search engine has tried and failed to fetch, and often includes historic URLs no current crawl would surface.
Prioritise by traffic, not by count
A broken link on your main service page matters more than fifty broken links in blog posts from 2018. Sort by the traffic the linking page receives, and fix downward from there.
Fix at the source
For each broken link, either correct the link to point at the right page, or if the destination genuinely moved, put a redirect in place and still correct the link. Relying on the redirect alone leaves a hop in every journey and keeps the wrong URL circulating.
Then make it routine
Run the crawl monthly. Broken links accumulate from ordinary editing — a page renamed, a service retired, a typo in a hand-written href — and a monthly check keeps the number in single figures rather than the hundreds.
Frequently asked questions
What is the primary tool for finding broken links?
A site crawler that follows every link outward and records each destination's status. Configure it to render JavaScript, include images and PDFs, and run it against the live site rather than staging.
What does a crawl miss?
Orphaned pages nothing links to, links behind forms or logins, links inside PDFs, content that only renders on interaction, and email templates — where broken links usually cost more than on-site ones.
Why read the server logs?
They show real 404s as they happen, including requests a crawl would never make — mistyped URLs, links from other sites, old bookmarks — and the referrer tells you whose link is broken.
How should I prioritise fixes?
By the traffic of the page containing the link, not by the number of broken links. One broken link on a main service page matters more than fifty in old blog posts.
Is a redirect enough, or should I fix the link?
Fix the link as well. Relying on the redirect leaves an extra hop in every journey and keeps the wrong URL circulating through your own site.