Most internal link audits fail in one of two ways. Either they produce a 4,000-row export that nobody acts on, or they fix things in the wrong order — rewriting anchor text on links that point at pages which then get merged and redirected a week later. This checklist is built to avoid both: twenty checks, grouped so that each step only touches links the previous steps have already cleaned up, and each one with a clear definition of done.
If you want a quick read on where your site stands before committing an afternoon, the internal linking health quiz is a two-minute self-assessment that tells you which sections below are likely to matter most for you.
How to use this checklist
The order matters more than it looks. Broken links and redirects come first because they are unambiguous and change which URLs exist. Reachability — orphans, dead ends, depth — comes next, because you cannot judge whether a page has the right links until you know it has any. Anchor text and competing posts come last, because deciding which of two posts should win changes where dozens of links ought to point.
Every check below has three parts:
- Why — what goes wrong for readers or crawlers if you skip it.
- Check — a free way to do it, then the faster way with a crawler. The crawler examples use Screaming Frog SEO Spider, because its free version crawls up to 500 URLs and many people already have it; the filter names quoted are the ones in its user guide. Sitebulb and the site-audit tools in Ahrefs and Semrush report the same things under other names, and our comparison of Silotree and Screaming Frog covers where a desktop crawler is the better tool.
- Fixed — what the export looks like when you are done, so you know when to stop.
Keep one spreadsheet for the whole audit, with a tab per section and a “date fixed” column. It is the only way to tell later which change did what. And if the bigger picture — why internal links matter at all — is new to you, the internal linking strategy guide is the place to start.
Before you start: the crawl and the URL list
Twenty minutes of setup decides whether the rest of the audit is accurate. A crawl that starts on the wrong hostname, or ignores your sitemap, will report problems you do not have and miss ones you do.
- 1. Configure the crawl to see what Google sees
Why: a crawl that starts at
http://or the wrong host, or ignores robots.txt, reports a site that no reader or search engine actually sees.
Check: start from the exact home page address your site redirects to. Respect robots.txt. Leave “follow internal nofollow” off for the main crawl so the numbers match how links are meant to be read. Run it once without JavaScript rendering, so you see the links in the HTML your server sends; check 20 compares that against a rendered crawl. Keep the speed low enough that your host does not start answering with errors.
Fixed: the first row of the crawl is your canonical home page with a 200, and the crawl finishes without a wall of 429 or 503 errors. - 2. Build the list of URLs that should exist
Why: a link-following crawl only finds pages that are linked. To see what it missed, you need a second list from somewhere else.
Check: export every URL from your XML sitemap —/wp-sitemap.xmlon WordPress 5.5 and later; with Rank Math it is/sitemap_index.xml, and in Yoast SEO, Settings → Site features → XML sitemaps has a “View the XML sitemap” link. Add the Pages export from Search Console’s Performance report for the last 12 months. Put both in one tab and remove duplicates. In a paid crawler, add the sitemap to the crawl configuration and it will do the comparison for you.
Fixed: one de-duplicated column of every URL you want indexed, plus any URL that earned clicks — including the ones you forgot about. - 3. Record a baseline before you change anything
Why: without “before” numbers you cannot tell whether the audit helped, or whether a later drop was caused by it.
Check: save the crawl, and export clicks and impressions per page from Search Console for the last three months. Note the date.
Fixed: a dated folder with the crawl file and two exports you can compare against in eight weeks.
Broken links, redirects and URL variants
These are the checks with no judgement involved. A link either reaches a working page in one step or it does not. Fix them first, because several later checks — anchor text, inbound link counts — are distorted by links that point at the wrong address.
- 4. No internal link returns a 4xx
Why: a broken link is a dead end for the reader and a wasted request for the crawler, and whatever the old page had built up stops at the 404.
Check: free: the free internal link checker lists every broken internal link with the post it sits in; the Redirection plugin’s 404 log (Tools → Redirection → 404s) shows which broken addresses visitors actually hit. Crawler: Response Codes → Internal → Client Error (4xx), then export the inlinks to see every source page.
Fixed: zero internal links to a 4xx. Each was either pointed at the right live page or removed; deleted pages that had traffic or backlinks have a 301 to their closest replacement. - 5. Internal links point at final URLs, not redirects
Why: a link through a redirect still works, but every visit costs an extra request, and your own site keeps naming an address you retired. Google uses a permanent redirect as a signal that the redirect target should be canonical; your links should agree with it.
Check: free: the same link checker reports links through redirects separately from broken ones. Crawler: Response Codes → Internal → Redirection (3xx), and export the inlinks.
Fixed: every link in post content, menus and widgets names the final address. The redirects themselves stay in place for bookmarks and backlinks. - 6. No redirect chains or loops
Why: a redirect chain is slower for everyone, and Google documents that its crawlers follow up to 10 redirect hops before giving up. Chains usually come from a slug renamed twice, or an http → https redirect stacked on a www → non-www one.
Check: free:curl -sIL https://example.com/old-slug/prints every hop. Crawler: Reports → Redirects → Redirect Chains.
Fixed: every redirect goes straight to a 200 in one hop, and no internal link starts a chain. - 7. One version of every URL: https, one host, one trailing-slash style
Why: sites that moved to https years ago often still have hundreds of
http://links in old posts, each one a redirect. Google says to link to the canonical URL rather than a duplicate. WordPress’sredirect_canonical()redirects the wrong host and trailing-slash form on requests, so those links still work — but each one is a redirect your own content triggers.
Check: free: the WP-CLI commands below;wp search-replace --dry-runreports what it would change without saving anything. Crawler: filter the redirect export forhttp://,www.or a missing trailing slash.
Fixed: a dry run finds zero matches, and the redirect export has no protocol, host or slash variants left.
# Which published posts still link to the http:// version of your own site?
wp db query "SELECT ID, post_title FROM $(wp db prefix)posts
WHERE post_status = 'publish'
AND post_content LIKE '%href=\"http://example.com%'"
# Preview the fix (changes nothing), then run it without --dry-run once you have a backup.
wp search-replace 'http://example.com' 'https://example.com' --dry-run --preciseOrphans, dead ends, depth and archives
With every link pointing at a real page, you can now ask which pages your links actually reach — and how easily.
- 8. No important page is an orphan
Why: an orphan page is reachable only through the sitemap or from outside your site. Your own pages never vouch for it, and readers can never get there from a related post.
Check: compare the URL list from check 2 with the crawl: any sitemap URL the crawl never reached is a true orphan. For posts that are linked only from archives, count links from inside post content. The orphan pages guide has four ways to do it, including a free WP-CLI script.
Fixed: every page you want found has at least two in-content links from related posts; the rest are merged, redirected or deliberately left standalone. - 9. No dead ends in your content
Why: a dead-end page has nowhere to send a reader who has just finished it — except back to the search results.
Check: free: the link checker flags dead ends. Crawler: Links → Pages Without Internal Outlinks. Most crawlers count menu links, so also sort by in-content outlinks if yours can separate them.
Fixed: every post has at least one or two links in its body to the next thing a reader would want — the next step of a recipe method, the gear list for a hike, the setup guide after an overview. - 10. Important pages are within three clicks of the home page
Why: click depth is how far your own structure puts a page from the front door. Google’s John Mueller has said what matters is how many links you have to click through to reach content, not how many slashes its URL has. Readers rarely dig past a few clicks either.
Check: free: the click depth checker or the link checker. Crawler: the Crawl Depth column, or Links → Pages With High Crawl Depth.
Fixed: money pages and best evergreen posts sit at depth 3 or less, usually by being linked from a hub page that is in the menu. The click depth guide explains why three is a habit, not a rule. - 11. Pagination and archives are crawlable but not your main route
Why: Google asks that paginated pages each have a unique URL and a normal link to the next page, and that you do not canonicalise page 2 onwards to page 1. But a post reachable only through page 30 of “older posts” is reachable in name only.
Check: open/page/2/of your blog and a category: does each have its own URL and a real<a href>“next” link? In the crawl, sort by depth and see how many posts are found only through/page/URLs.
Fixed: pagination works without JavaScript, page 2 onwards is not canonicalised to page 1, and no post you care about depends on pagination to be found.
Where the links point
Now the judgement calls. A page can be reachable and still get far fewer links than it deserves — or far more. The useful comparison is links against value.
- 12. Your most valuable pages have the most in-content links
Why: inbound internal links are how your site tells crawlers which pages matter. Zyppy’s study of 23 million internal links across 1,800 sites found pages with more inbound internal links tended to get more search clicks — a correlation, not proof, but a consistent one. On many sites the counts follow age, not value: the oldest posts have the most links.
Check: export unique inlinks per URL from the crawl into a tab calledInlinks. Next to your Search Console Pages export (or a list of money pages — a plumber’s service pages, a shop’s best sellers, a SaaS help centre’s setup guides), look up each count with the formula below and sort by clicks.
Fixed: your top 20 pages by clicks or revenue each have more in-content inlinks than the site median. A personal-finance blog whose best-earning comparison post had 3 inlinks against a median of 7 would add 5–10 from related posts. - 13. Sitewide links go where you mean them to
Why: a link in the menu, footer or sidebar is repeated on every page, so a 600-post site gives each sitewide target 600 inlinks. If those targets are a tag cloud, a login page or a 2021 giveaway, your structure is shouting about the wrong pages. The same Zyppy study saw traffic stop rising past roughly 45–50 inbound links and suggested sitewide navigation links to low-traffic pages as part of the reason.
Check: sort the crawl by inlinks, highest first. Anything near the top that is not your home page, a hub or a key page is a sitewide link worth questioning. Pages with hundreds of outlinks (mega menus, long footers) show up under Links → Pages With High Internal Outlinks.
Fixed: the ten most-linked URLs are ones you would choose. The footer and sidebar hold a short, deliberate list. - 14. No nofollow on internal links
Why: nofollow on your own links does not save value for other pages. Google has treated nofollow as a hint for ranking since September 2019, and for crawling since March 2020, and for keeping crawlers away from parts of your own site it points to the robots.txt disallow rule rather than nofollow. Internal nofollow is often a leftover from a theme or plugin setting.
Check: free: view source on a few posts and search fornofollow. Crawler: Links → Internal Nofollow Outlinks.
Fixed: no internal nofollow, except possibly on links such as login or cart pages that are also blocked from crawling. - 15. No internal links to noindexed or canonicalised URLs
Why: linking to a page marked noindex, or to a URL whose canonical tag names a different page, spends your links on an address you have asked Google to keep out of its results or to treat as a duplicate. Typical cases: a recipe’s print view, a product variant URL, a
?replytocom=link, a tag archive you noindexed.
Check: crawler: Links → Non-Indexable Page Inlinks Only, the Directives tab’s Noindex filter and the Canonicals tab’s Canonicalised filter, each with its inlinks exported. Free: open your most-linked targets and search the page source fornoindexandcanonical.
Fixed: in-content links point at indexable, self-canonical URLs. Navigation links to noindexed pages are fine if readers need them.
=IFERROR(VLOOKUP(A2, Inlinks!A:B, 2, FALSE), 0)Anchor text and competing posts
Anchor text is the part of an audit people most enjoy and most often overdo. Google’s own guidance is modest: anchor text should be descriptive, reasonably concise and relevant, and “click here” is its example of too generic. The four checks below look for patterns, not for individual links to rewrite.
- 16. Few generic anchors in post content
Why: “click here”, “this post” and “read more” tell neither the reader nor the crawler what is on the other side.
Check: free: the link text analyser. Crawler: Bulk Export → Links → All Inlinks, then filter the anchor column, or Links → Non-Descriptive Anchor Text In Internal Outlinks.
Fixed: generic anchors survive only where the sentence around them makes the destination obvious. A “here” in “I tested twelve tents; the full results are here” is fine; a column of “read more” buttons is not content. - 17. No page receives the same exact-match anchor from everywhere
Why: if forty posts link to your sourdough guide with the words “sourdough starter”, the repetition reads as mechanical, and Google’s link guidance warns against cramming keywords into anchors. Exact match itself is not the problem: in the Zyppy data, pages with at least one exact-match anchor had about five times the traffic of pages with none, and more varied anchors went with more traffic.
Check: in the All Inlinks export, make a pivot table of target URL × anchor. Look for any target where one anchor makes up most of its inlinks.
Fixed: anchors vary with the sentence they sit in; a few use the exact phrase, most describe the page in the linking post’s own words. - 18. The same anchor does not point at different pages
Why: if “best budget tent” links to one post from your camping guide and a different post from your gear round-up, your own site is undecided about which page answers that phrase — and so is Google.
Check: the same pivot, flipped: anchor × target URL. Any anchor with two or more distinct targets is a candidate. Ignore generic and navigational anchors.
Fixed: each topical anchor points at one page. Where two pages really cover the same thing, that is check 19. - 19. No two posts compete for the same search
Why: keyword cannibalization (also spelled cannibalisation) splits clicks and links between two pages, and often neither ranks as well as one would.
Check: free: in Search Console, open a query in the Performance report and switch to Pages; two or more pages taking impressions for the same query is the sign. The keyword cannibalization checker does it across all queries. The keyword cannibalization guide shows how to tell real competition from two pages that legitimately share a query.
Fixed: each competing pair has a decision — merge and redirect, re-target one, or link them so the winner is clear — and internal links point at the winner. The guide to merging, redirecting or retargeting competing posts walks through each option.
Links a crawler cannot follow
One check, but on some sites it is the whole audit. Google’s JavaScript documentation says it can only discover links that are <a> elements with an href. A “link” built from a <span> with a click handler, or a button that changes the page with JavaScript, may work for readers and be invisible to crawlers.
- 20. Every link that matters is a real <a href> in the HTML
Why: related-posts widgets, tabbed content, “load more” buttons, filter menus on a shop and some page-builder elements produce links only after JavaScript runs, or produce no
hrefat all. Google does render JavaScript, as a separate step after crawling, and its link guidance marksonclickandjavascript:links as not recommended.
Check: free: open a post, view source (not Inspect) and search for a few link targets you can see on the page. If a link is visible but not in the source, it is added by JavaScript. Crawler: run a second crawl with JavaScript rendering on (a paid feature in Screaming Frog) and use the JavaScript tab’s Contains JavaScript Links filter.
Fixed: every in-content and navigation link is a plain<a href>in the HTML your server sends, and “load more” or infinite scroll is backed by paginated URLs.
Search Console’s Links report shows internal links as Google has found them. Google describes it as a sample of your links rather than a full inventory, and the tables stop at 1,000 rows, so use it to sanity-check your crawl rather than replace it. If a page your crawl shows as well linked has almost no internal links in Search Console, check 20 is the first place to look.
Prioritising what you found
A first audit on a five-year-old site typically turns up something in most of the twenty checks. You will not fix everything this month, and you do not need to. Rank each finding by how much it hurts readers and crawlers (severity) against how long it takes to fix (effort), and start in the top-left of that grid.
| Finding | Severity | Effort | When |
|---|---|---|---|
| Broken internal links (4) | High | Low | This week |
| Links through redirects, chains, http links (5–7) | Medium | Low — usually one search-replace | This week |
| JavaScript-only navigation or in-content links (20) | High | High — needs a theme or plugin change | Plan it now; fix this quarter |
| Orphaned money pages or best posts (8) | High | Medium | This month |
| Under-linked valuable pages (12) | High | Medium | This month, top 20 first |
| Competing posts (19) | High | High — a decision per pair | This quarter, biggest query first |
| Deep important pages (10) | Medium | Medium — a hub or menu change | This month |
| Internal nofollow, links to noindex or canonicalised URLs (14–15) | Medium | Low | This month |
| Sitewide links to low-value pages (13) | Medium | Low — one template edit | This month |
| Dead ends (9) | Low–medium | Medium | Fold into regular editing |
| Repeated exact-match, one anchor to two pages (17–18) | Low–medium | Medium | After competing posts are settled |
| Generic anchors (16) | Low | Medium | When you next edit each post |
| Pagination and archives (11) | Low unless broken | Low–high | Only if pagination fails check 11 |
Two rules keep the order honest. First, settle competing posts before you touch anchor text: there is no point varying the anchors on forty links that are about to be repointed at a different post. Second, when you fix an orphan or an under-linked page, link from a sentence the linking post already contains. Two or three good contextual links from related posts beat ten pasted into a “related reading” list.
A worked example. A travel site with 420 posts runs the checklist and finds 37 broken internal links, 212 links through redirects (almost all http:// from before an https move), 46 in-content orphans, 9 of its 20 top-earning itineraries below the median inlink count, and three pairs of competing Lisbon posts. Monday: one search-replace fixes the 212, an hour fixes the 37. That week: link the nine itineraries from two or three related posts each. That month: triage the 46 orphans. That quarter: decide the three Lisbon pairs, then repoint their links.
How often to run it
An audit is a snapshot, and sites drift. Posts get renamed, menus change, plugins come and go. A light, regular check catches drift while it is a handful of links rather than hundreds.
| When | Checks | Time on a few hundred posts |
|---|---|---|
| Monthly | Broken links, redirects and chains, new orphans (4–6, 8) | 15–30 minutes |
| Quarterly | The full checklist, compared against last quarter’s spreadsheet | Half a day |
| After a big change | Migration, https or domain move, permalink change, redesign, new menu, merged posts: checks 1–11 and 20 | Same day as the change |
| On publish | Link the new post from two or three older ones; check it is not a dead end | Five minutes per post |
The on-publish habit does more than the quarterly audit. A post linked from older posts on the day it goes live never becomes an orphan, and the quarterly list stays short.
Where Silotree fits
Every check above can be done with free tools and a spreadsheet. Silotree’s free link checker, linked in check 4, covers checks 4, 5, 8, 9 and 10 in one crawl of your published pages, with no account or email. In the WordPress plugin, broken internal links and links through redirects get a one-click fix on every plan, and the fix adds no new link. Competing posts are detected from your Search Console queries, with a suggested winner and a one-click repoint of internal links to it. For checks 8 and 12, it suggests contextual links from sentences you already wrote, and you approve or skip each one. The plans and their page limits are on the pricing page.
- SEO link best practices for Google — Google Search Central Crawlable <a href> links, JavaScript links, anchor text.
- How HTTP status codes affect Google’s crawlers — Google for Developers Up to 10 redirect hops; soft 404s.
- Redirects and Google Search — Google Search Central Permanent and temporary redirects.
- How to specify a canonical URL — Google Search Central Redirects as a canonical signal; link to the canonical URL.
- Pagination, incremental page loading, and their impact on Google Search — Google Search Central
- Block search indexing with noindex — Google Search Central
- Evolving “nofollow” – new ways to identify the nature of links — Google Search Central Blog, September 2019 Nofollow as a hint; for crawling and indexing from 1 March 2020.
- Links report — Search Console Help
- Qualify your outbound links to Google — Google Search Central Use robots.txt, not nofollow, for links within your own site.
- Understand JavaScript SEO basics — Google Search Central
- Google: click depth matters more for SEO than URL structure — Search Engine Journal, June 2018 Reports John Mueller in a Webmaster Central hangout.
- 23 million internal links — SEO case study — Zyppy (Cyrus Shepard) Correlation study of 1,800 sites; the author calls it directionally useful.
- New XML sitemaps functionality in WordPress 5.5 — Make WordPress Core
- redirect_canonical() — WordPress Developer Resources
- wp search-replace — WP-CLI documentation
- SEO Spider tabs user guide — Screaming Frog
Questions people ask
How long does an internal link audit take?
On a site of a few hundred posts, the crawl takes minutes and working through the twenty checks takes an afternoon. The fixing takes longer, which is why the checklist ends with a priority table: do the cheap, serious fixes first and schedule the rest.
Do I need a paid crawler to audit internal links?
No. A free crawl of up to a few hundred URLs, your XML sitemap and Google Search Console’s exports cover almost every check. A paid crawler mainly saves time on large sites and adds conveniences like sitemap-versus-crawl comparison and JavaScript rendering.
What is the most important thing to check first?
Broken internal links and links through redirects, because they are unambiguous and quick to fix. After that, orphans and under-linked money pages usually have the biggest effect, since they decide which of your best pages readers and crawlers can actually reach.
Should I fix every redirect in my internal links?
Fix the ones in your own content and templates, because updating a link to its final address is a two-second edit that removes a wasted request. Keep the redirects themselves in place for old bookmarks and backlinks; you are changing what you link to, not removing the redirect.
Is having many links to the same page a problem?
Not by itself. It becomes worth a look when a page with little value — a tag archive, a login page, an old promotion — receives far more internal links than your important pages, usually because it sits in a menu, footer or widget on every page.
How often should I audit internal links?
A short check of broken links, redirects and new orphans once a month, and the full checklist once a quarter. Also run it after anything that changes many URLs or templates at once: a migration, a permalink change, a redesign, or merging posts.
