Internal Linking Strategy at Scale
Turn internal links into a deliberate system - hubs, clusters and anchor discipline across thousands of pages.
On a ten-page site you link by hand. On a ten-thousand-page site, internal linking becomes an architecture problem: which pages deserve authority, and how does it flow to them?
Think in hubs and spokes
Every important topic gets a pillar (hub) page. Supporting articles (spokes) link up to the hub with descriptive anchors, and the hub links back down to each spoke. This concentrates relevance and tells search engines you cover the topic in depth.
Find and fix the weak spots
- Orphans - pages with zero internal links pointing in. Crawl the site and diff the crawl against your sitemap; anything in the sitemap but not reached is an orphan.
- Deep pages - anything more than 3-4 clicks from the homepage gets crawled less. Pull it up with links from stronger pages.
- Wasted authority - your strongest pages (most backlinks) should link to the pages you actually want to rank, not just to the privacy policy.
Anchor text discipline
Use varied, descriptive anchors that match the target's intent - never a wall of "click here". But do not force an exact-match keyword into every link; natural, contextual phrasing reads better and is safer. Contextual links inside body copy carry more weight than a link buried in a mega-footer.
Example
<!-- Spoke article linking UP to its pillar with a descriptive anchor -->
<p>This is one method in our full
<a href="/coffee/brewing-guide">coffee brewing guide</a>,
which compares every popular technique side by side.</p>
<!-- Pillar page linking DOWN to each spoke -->
<ul>
<li><a href="/coffee/pour-over-guide">Pour over: clean and bright</a></li>
<li><a href="/coffee/french-press-guide">French press: rich and full-bodied</a></li>
<li><a href="/coffee/aeropress-guide">AeroPress: fast and forgiving</a></li>
</ul>When to use it
- An SEO lead builds a hub-and-spoke architecture for a 5 000-page site by defining explicit link rules: every cluster article must link back to its pillar, and every pillar links to at most 20 clusters.
- A content team uses a keyword-to-URL mapping spreadsheet as the source of truth for anchor text, ensuring no two pages use the same exact-match anchor text for different target URLs.
- A developer builds an automated internal link suggestion system that scans new article drafts and recommends the 3 most relevant existing pages to link to based on keyword overlap.
More examples
Internal link audit: find orphan pages
Diffing crawled URLs against linked URLs exposes orphan pages that receive no PageRank from internal links and are therefore under-crawled and under-ranked.
python3 - << 'EOF'
# Compare all crawled URLs to all href targets to find pages with no inbound links
import json
# Simulated crawl data (in production: Screaming Frog CSV export)
crawled_urls = {
"/seo-guide/", "/seo-guide/keyword-research/",
"/seo-guide/technical-seo/", "/old-forgotten-page/"
}
linked_urls = {
"/seo-guide/", "/seo-guide/keyword-research/",
"/seo-guide/technical-seo/"
}
orphans = crawled_urls - linked_urls
print(f"Orphan pages ({len(orphans)}):")
for p in sorted(orphans):
print(f" {p}")
EOFAnchor text diversity check
Auditing inbound anchor text distribution for key pages catches over-optimisation (too many exact-match anchors) and weak anchors ('click here') that waste link equity.
python3 - << 'EOF'
# Audit anchor text distribution for a target URL
from collections import Counter
# In production: extract from Screaming Frog 'Inlinks' export
inbound_anchors = [
"keyword research guide",
"keyword research guide",
"keyword research",
"how to do keyword research",
"click here", # weak anchor
"keyword research guide",
]
counts = Counter(inbound_anchors)
print("Anchor text distribution for /seo-guide/keyword-research/:")
for anchor, count in counts.most_common():
flag = "OVER-USED" if count > 3 else ("WEAK" if anchor in {"click here", "read more"} else "OK")
print(f" [{flag}] {count}x '{anchor}'")
EOFAutomated internal link suggestions
Matching new article keywords against existing page keyword sets automates the internal link suggestion process, ensuring every new piece integrates into the content cluster.
python3 - << 'EOF'
# Match new article keywords against existing page keyword maps
new_article = {
"title": "Long-Tail Keyword Research: A Complete Guide",
"keywords": {"long-tail keywords", "keyword research", "search volume", "keyword difficulty"}
}
existing_pages = [
{"url": "/seo-guide/keyword-research/", "keywords": {"keyword research", "search volume"}},
{"url": "/seo-guide/search-intent/", "keywords": {"search intent", "keyword research"}},
{"url": "/seo-guide/technical-seo/", "keywords": {"crawlability", "indexing"}},
{"url": "/seo-guide/head-vs-longtail/", "keywords": {"long-tail keywords", "head terms"}},
]
for page in existing_pages:
overlap = new_article["keywords"] & page["keywords"]
if overlap:
print(f"Link to: {page['url']} (shared: {', '.join(overlap)})")
EOF
Discussion