Skip to main content

Internal link audit: find orphan pages and weak links

A 6-step internal link audit, run on our own site: 337 pages, 15,850 links, 8 orphan pages and what I did with them. Redirects, anchors, click depth, nofollow.

Founder, CometWeb

I build CometWeb Insight, a website audit app that ends with a ranked to-do list. I write about what I measure on real sites: performance, SEO, accessibility and CO₂e.

Published: Updated:
20 min read

My crawler checked 15,850 internal links on CometWeb and found that they all led directly to working pages. The broken-link report looked clean. But when I compared the pages reached by the crawler with the sitemap, eight older articles were missing from the crawl.

The articles were still online and listed in the sitemap. No crawlable internal link led to those pages from the entry points I tested. An internal-link audit therefore needs to compare link paths, discovered URLs and the sitemap, not just count HTTP errors.

337 HTML pages reached from the two homepages; 273 of them indexable ?
8 sitemap URLs that no internal link reaches: orphan pages ?
0 of 15,850 internal links point at a redirect or an error ?
2 clicks: the deepest any indexable page sits from its own homepage ?

Internal links: what links between your pages do

Internal links are links between pages on the same site. An internal link audit checks four things:

  1. that every page you care about can be reached through links a crawler can read,
  2. that those links use descriptive anchor text, the clickable words of the link,
  3. that they point straight at the final, canonical URL,
  4. that your most important pages get enough links from related content.

You fix all of it in your own templates and content, and the links themselves do three jobs.

Discovery. According to Google's SEO starter guide, Google finds pages primarily through links from pages it has already crawled. Google's link best practices ask for a link to every page you care about from at least one other page on your site.

Context. Anchor text tells users and Google what's on the other side, and when an image is the link, Google takes its alt text as the anchor.

Signals between pages. Where you link from says which pages you consider important, but how much signal a link passes, Google doesn't publish. Our glossary entry on link equity separates what's documented from common assumptions.

Internal vs external links

Internal linksExternal links
Where they pointAnother page on the same siteA page on a different site
Who controls themYouThe site that links, or you for outbound links
Main job in an auditDiscovery, context, reaching key pagesQualifying outbound links (sponsored, ugc, nofollow) and earning inbound ones
Typical problemsOrphan pages, links to redirects or 404s, generic anchors, pages buried deepBroken outbound links, paid links not marked as such

Step 1: Crawl your internal links from the homepage

Start where a search engine would, at your homepage, and have your crawler follow <a href> links and record where each one leads. Export one row per link:

FieldWhy you need it
Source URLWhere the link sits. You'll edit this page
Target URLWhere the link points, exactly as written
Anchor textWhat the link says (or the alt text for image links)
Target status code200, 301, 302, 404, 5xx
Final URL after redirectsWhere the link really ends up
rel valuenofollow, sponsored, ugc or none
Link positionHeader, navigation, footer, body content, if the tool can tell
Click depth of the targetShortest number of clicks from the homepage

Keep a second export per page with the URL, status, indexability, canonical target and inlinks, the number of unique internal pages linking to it.

What my crawl recorded on cometweb.io

My crawler (Python standard library only) made one request at a time, obeyed robots.txt and fetched plain HTML without JavaScript. It reached 337 HTML pages carrying 15,850 internal links, a median of 47 per indexable page (range 37 to 93). But where those links sit matters more than their number.

Page template of cometweb.io with its regions marked: footer 10,596 internal links, body content in main 2,241, header with menu 2,131, navigation in main 682, sidebar 200. 15,850 links in total.
The footer and header supply most links, while body content in main carries only 2,241 of 15,850.Crawl of cometweb.io, 24 Sep 2026

So count unique linking pages and record where each link sits, because a menu item repeated on every page is one decision made in one template. I nearly got caught by this myself, because my first run lumped breadcrumbs, the table of contents and related posts in with the main menu, so contextual links looked thinner than they are. I fixed the rule and only publish the second run.

Of my 337 pages, 17 were noindex research files, 10 were noindex product pages and 37 were parameter variants canonicalised to the clean URL. That leaves 273 sitemap URLs, and I use them for the distributions below.

Step 2: Find orphan pages by comparing the crawl with your sitemap

An orphan page is a URL that exists and matters to you, but that no other page on your site links to. A crawler that starts from the homepage will miss it, so compare the crawl with lists that are independent of links:

  1. XML sitemap (see XML sitemap), the URLs you've declared worth indexing.
  2. Search Console, meaning pages with impressions and URLs from the Page indexing report.
  3. Analytics, meaning landing pages with visits in the last few months.
  4. CMS or database export, meaning every published page, including the forgotten ones.

Merge your lists, normalise the URLs (protocol, host, trailing slash) and subtract everything your crawl reached, then decide on each candidate separately:

What the orphan isWhat to do
A page you want to rankLink to it from relevant pages and, where it fits, from a hub or category page
An outdated duplicate of another pageRedirect it to the current page and remove it from the sitemap
A campaign or test page with no futureRemove it, or keep it out of the index with noindex
A page reachable only after login or a formBeing an orphan is fine here. Just keep it out of the sitemap

Google's sitemap documentation says a sitemap helps discovery but doesn't guarantee that its URLs will be crawled and indexed. It describes proper linking as reaching every important page from your menu or from links on your pages. In plain English: the sitemap is a wish list, and links are the roads.

Eight orphan pages on cometweb.io and what I did with them

Graph of 273 cometweb.io URLs connected by links from the homepage, with 8 orphaned URLs beside it that were in the sitemap only. The sitemap listed 281 URLs.
Only subtracting the crawl from the sitemap exposed the eight orphans, and since I compared just those two lists, eight is a floor.Crawl of cometweb.io, 24 Sep 2026

My 8 orphans were four English posts on branding, customer loyalty and marketing strategy, plus their Polish versions. Each returned 200 with a self-referencing canonical and without noindex.

When I narrowed the blog to technical topics, a category filter took them off the blog index. I kept the URLs live for visitors from search, but the sitemap generator didn't know about that filter.

Each decision made sense on its own, but together they produced exactly what Google warns about: a sitemap URL with no navigation leading to it. In Search Console, the eight posts together had 1 click and about 166 impressions over 90 days, on queries unrelated to site audits. They don't fit anything I write now, so linking them from my audit articles made no sense.

I went with the third row of the table, the noindex option, so that same day the posts got noindex, follow in the meta tag and in the X-Robots-Tag header, and they dropped out of the related-posts block. The sitemap went from 281 to 273 URLs, exactly the ones the crawl reached. The post URLs still answer 200, so anyone with a link lands on a working page.

Step 3: Fix internal links that point at redirects or errors

Filter your link table for targets that don't return 200:

  • 404 and 5xx targets. Point the link at a working page or remove it, and fix your templates first, because a broken link in the navigation or footer repeats on every page.
  • Redirecting targets. Google's site-move guide says to change internal links to the new URLs and to redirect straight to the final destination. Googlebot can follow up to 10 hops, but Google recommends ideally 3 at most, because every hop adds latency. A single 301 still works, so fix chains and loops first.
  • Temporary redirects (302, 303, 307). According to Google's redirects documentation, Google follows them, but unlike 301 and 308 it doesn't treat them as a signal that the target is canonical. So an internal link through one sends a mixed message.
  • Links to non-canonical URLs, such as parameter versions, http where it should be https, or a trailing-slash variant. Google advises linking to the canonical URL, because consistent linking helps it understand which version you prefer.

Our redirect checker shows a chain hop by hop, and the canonical checker shows where a page's rel="canonical" points. I cover how canonical works with the sitemap and robots.txt in Canonical, sitemap and robots.txt.

Redirects and parameters on cometweb.io

None of the 15,850 internal links pointed at a redirect or an error. All 389 requests got a 200, and I still publish the empty redirect table in the pack, because it's a baseline for the next crawl after a migration or a menu change. The non-canonical case, the parameter variants, did turn something up.

Diagram: 30 cometweb.io pages carry 44 internal links to 37 URLs with parameters. 40 links to /contact?topic= stay, because the parameter changes the form. 4 links with source_page in 2 Polish posts need fixing.
A parameter that changes the page stays, so of 44 links on 30 pages I only fix 4, and all 37 target URLs were canonicalised to their clean version anyway.Crawl of cometweb.io, 24 Sep 2026

The four links to fix sit in two Polish posts, because on crawl day the English posts already linked to the clean URL.

Step 4: Check the anchor text of internal links

Sort your link table by anchor text and read the most common values, because Google lists "click here", "read more", "website" and "article" as examples of anchors that are too generic. You're looking for four things:

  • Generic anchors on links to important pages. Say what the target is: "pricing for agencies" instead of "here".
  • Empty anchors. Image links without alt text and icon links without an accessible name give zero context.
  • The same anchor pointing at different pages. Two pages both linked as "SEO audit" compete for the same meaning.
  • Over-long anchors. A whole sentence as a link is hard to scan, so keep it to a few words.

You can put the keyword in your own words, because Google asks for a natural, specific description of the target.

Anchors on cometweb.io

The crawl found 9 links with generic anchors on 5 pages, and zero empty ones. "Learn more" and "Dowiedz się więcej" appear three times each on the two noindex versions of the products overview, and there's also "View all" on both blog indexes and "Artykuł" on a research page. I'd start with "View all", since the blog index is indexed and linked from every footer.

I also logged two patterns that look suspicious but are fine. The first is 52 card links (44 tools, 8 ebooks) have an aria-label that differs from their visible text, so my table keeps both.

The second is 30 anchor texts outside the header and footer that lead to more than one target, such as "View module" on seven module cards. That's expected on a card grid and would be a problem in body text.

Step 5: Check the click depth of your important pages

Click depth is the shortest path from the homepage to a page, and Google publishes no depth limit, so treat depth as a comparison. List your money pages and check where they sit. If your core service page is five clicks deep while old news posts sit two clicks from the homepage, your structure says the news matters more. Fix it with a link from the menu or a hub page, links from related articles, or shorter pagination.

Click depth on cometweb.io

Each language version has 1 homepage, 41 pages one click away and 93 two clicks away. Blog posts, glossary terms and most free tools sit at depth 2, because the footer links their index page.

The four unreached URLs per language are the eight orphans from step 2, shown before I dropped them from the sitemap. On a site this shallow, a URL with no path at all can't be blamed on depth. That's the limit of depth as a metric, because the footer makes the site shallow, and depth tells you nothing about how well content connects your pages.

Step 6: Check nofollow and internal links a crawler can't follow

Internal nofollow. Google documents nofollow, sponsored and ugc for outbound links you don't want to vouch for. For your own pages, it points you to a robots.txt disallow rule to stop Google fetching a page, or to noindex, with crawling allowed, to keep it out of the index. An internal nofollow is usually a leftover from old "PageRank sculpting" advice, so remove it from links to pages you want found, and use noindex or robots.txt for the rest.

Links a crawler can't extract. Google can only reliably crawl a link that's an <a> element with an href attribute. Navigation built from <span> or <button> elements with onclick handlers, or router attributes without an href, works for users and can be invisible to crawlers.

Crawlable:
<a href="https://example.com/services/seo-audit">SEO audit service</a>

Not reliably crawlable:
<span onclick="goTo('/services/seo-audit')">SEO audit service</span>
<a onclick="goTo('/services/seo-audit')">SEO audit service</a>

Compare a crawl with JavaScript rendering against one without, or check that your menu items appear as plain <a href> in the rendered HTML.

Nofollow and rendering on cometweb.io

Zero internal links on cometweb.io carry nofollow, and the server HTML of the 337 pages has zero <a> elements without an href. I also loaded eight pages in Playwright's bundled Chromium: both homepages, both blog indexes, both versions of this article, plus the tools and glossary indexes. On all eight, the internal link targets in the live page matched those in the server HTML.

Eight pages are a sample, and nothing was clicked or hovered, so links that appear only after a menu opens weren't compared. On a single-page application, it's the first check I'd run.

How many internal links should a page have?

There's no official number of internal links per page, and Google's link best practices say plainly that there's no magical ideal number. A practical rule works better: link where a visitor would actually want to go next. An article about redirect chains needs a link to the redirect checker and to the migration guide, while twenty links to unrelated services won't help your reader.

Ask yourself three questions in an audit:

  • Does every important page have links from pages on the same topic, or only from the footer?
  • Do the contextual links in the body get lost under the navigation links?
  • Would a reader notice if a link disappeared?

The inlink count is useful for comparison, because if your main service page has fewer internal links than a three-year-old blog post, your structure contradicts your priorities.

Inbound links on cometweb.io: all links vs content links

Counted naively, cometweb.io looks well linked: every indexable page has at least two linking pages, and 60 have 50 or more, all thanks to the templates. Leave out the header and footer, and the sidebar too, and 105 pages have two to four linking pages, 16 have one and 8 have none. These are different pages from the step 2 orphans, namely the bot page, the MCP connector and two legal pages, in both languages.

Of those 24 pages, the legal documents and the crawler user-agent page can reasonably rely on footer links. The other pages need links from relevant content; the table identifies them. On crawl day, a Polish article on page speed still linked to the English WOFF2 version, which I fixed the same day.

What the internal link audit found on cometweb.io

Results panel of the cometweb.io internal link audit from 24 Sep 2026: 0 redirects and errors, 8 orphaned posts (done), 4 links with a source parameter to fix, 40 links with a form topic that stay, 9 generic anchors and 24 pages with fewer than 2 content links.
The first row is the useful kind of boring, and the rest is small and cheap to fix.Crawl of cometweb.io, 24 Sep 2026

What to fix first in your internal linking

I work in this order:

  1. Broken links in templates (navigation, footer, sidebars), because one fix repairs every page.
  2. Orphan and weakly linked money pages. Add links from related articles and from the topic's hub page.
  3. Links to redirects after a migration. Use your redirect map to replace old URLs with the final ones in content and navigation, and in canonical tags.
  4. Generic and empty anchors on links to important pages.
  5. Internal nofollow and navigation a crawler can't read.

Then crawl your site again, and orphans, broken links and links to redirects should go down, and your most important pages should sit shallower. Keep your sitemap up to date along the way, but it's the links that lead to your pages. I cover indexing and performance in my technical SEO guide.

How I guard internal linking at CometWeb

Our pre-release quality gate includes an internal-link-graph test. It fails the release when a glossary term has no rendered link from another glossary entry, or when a free tool is missing from every other tool's "related tools" block, because such a page would be reachable only from an index.

Recently that test held back the new llms.txt generator until the robots.txt and sitemap tools linked to it. Google doesn't require this, but it's my own practice, and it catches an orphan at release.

The crawl showed where that gate stops, because it covered the glossary and tools, and the eight orphans were on the blog. After this crawl I added a second test that keeps archived posts out of the sitemap and the related-posts block.

Internal link audit in CometWeb Insight

You can do all of this by hand with a crawler and a spreadsheet. The Crawl module in CometWeb Insight, our website audit app, does most of these steps for you:

  • crawls public pages found through internal links, the sitemap or your own list,
  • checks HTTP status codes, redirects and redirect chains, plus internal links that lead to errors,
  • compares the crawl with the sitemap, when there is one, and lists orphan pages,
  • flags up to 10 pages with fewer than two internal links and suggests which pages to link from,
  • groups issues that repeat across templates and ranks pages by the number and weight of problems,
  • lets you re-check a single fixed link and compare two crawls.

Pages behind a login, or without links, may not make it into your crawl, and the methodology describes the scope of each check. To see this report for your own site, create an Insight account.

How I measured this and how to reproduce the audit

I ran the crawl on 24 September 2026, and it made 389 sequential requests in about 5 minutes without running JavaScript, so I checked rendering separately on 8 pages.

The methodology covers the definitions and limits, plus two corrections made before publishing. The same folder holds crawl.py and analyse.py, which you can point at your own site, the raw table of all 20,252 links (links.csv.gz), per-page numbers (page-metrics.csv) and summary.json with every number quoted above. Crawl only sites you own or may audit, keep it sequential and read robots.txt first.

Three takeaways from the audit

Three overlapping circles: the sitemap, a crawl from the homepage and links from content. A page is healthy in the overlap. On cometweb.io 8 URLs were in the sitemap only, and 24 pages had fewer than two content links.
Outside the overlap I found 8 orphans (sitemap without crawl) and 24 pages with fewer than two content links, even though the crawl reached them.Crawl of cometweb.io, 24 Sep 2026
  1. Subtract the templates. My footer carried 10,596 of 15,850 internal links, and only without it did 24 weakly linked pages show up.
  2. Subtract the crawl from the sitemap. The broken-link report was clean, yet 8 posts had zero links, and only the comparison exposed them.
  3. Catch orphans at release. My quality gate held back the llms.txt generator until it had links, so repeat the audit after changes that touch many pages at once.

Crawling 337 pages took me about 5 minutes, and deciding what to count took longer. So tomorrow morning, start with one subtraction: your sitemap minus a crawl from your homepage.

Frequently asked questions

Will Google index an orphan page?

An orphan page can get indexed if Google knows its URL from your sitemap or from links on other sites. But Google's documentation says a sitemap only helps discovery, and its link guidelines ask for a link to every important page from at least one other page on your site. Without that link, the page gets neither anchor-text context nor a signal from your own site that it matters.

Do footer and menu links count in an internal link audit?

Footer and menu links are ordinary a href links, so crawlers follow them. Google doesn't publish how it weighs links by their position on the page. In an audit, count them separately: on cometweb.io the footer carried 10,596 of 15,850 internal links, and without subtracting it every page looked well linked.

How often should you repeat an internal link audit?

Repeat an internal link audit after any change that touches many pages at once: a URL migration, a rebuilt menu, footer or post template, and a change to your blog categories. The eight orphan pages on cometweb.io came from exactly that kind of category filter change. Between audits, a test in your release process that blocks a page with no inbound links does a lot of the work.

Can you link internally to noindex pages?

Yes. A noindex page can still be useful to visitors, like the 10 noindex product pages on cometweb.io. For your own pages, Google recommends noindex with crawling allowed, so don't block such a page in robots.txt and don't add nofollow to links pointing at it. Link to it where readers look for it, and keep it out of the sitemap.

Sources

  1. Google Search Central: Link best practices for Google. Crawlable <a href> links, anchor text, alt as anchor text for image links, every important page linked from another page, no ideal number of links.
  2. Google Search Central: SEO starter guide. Pages found mainly through links, link text.
  3. Google Search Central: Learn about sitemaps. Sitemaps help discovery without guaranteeing crawling or indexing; proper linking.
  4. Google Search Central: How to specify a canonical URL. Link consistently to the canonical URL.
  5. Google Search Central: Redirects and Google Search. Permanent vs temporary redirects as canonical signals.
  6. Google Search Central: Site moves with URL changes. Update internal links, redirect to the final destination, hop limits, latency.
  7. Google Search Central: Qualify your outbound links. nofollow, sponsored and ugc; robots.txt and noindex for your own pages.
  8. CometWeb: internal link crawl of cometweb.io, 24 September 2026. First-party measurement: scripts, raw link table, results and limits.

Check your site in Insight

Free gives you one project and 60 credits a month. That covers a Standard audit with a priority list.

No credit card Report with date and sources Free account in the app