When most developers think of PageRank, they envision external backlinks from third-party websites. However, Google and modern search engines still rely heavily on Internal PageRank to calculate how to allocate their daily crawl budget across your domain.
If critical landing pages or pricing tiers are buried 4 or 5 clicks deep from the homepage with few incoming internal anchors, search bots rarely crawl or refresh them in search indices. Worse yet, orphan pages (pages with zero incoming links) are virtually invisible to search engines.
In ⚡ PLYXO (CRO • SEO • AIO • AEO • GEO), our crawler constructs a directed graph of all internal links to compute internal PageRank distribution programmatically.
1. The Internal PageRank Algorithm
We model your website as a directed graph $G = (V, E)$, where vertices $V$ are pages and edges $E$ are internal hyperlinks.
The PageRank formula distributes link equity iteratively:
$$\text{PR}(u) = \frac{1 - d}{|V|} + d \sum_{v \in B_u} \frac{\text{PR}(v)}{L(v)}$$
Where:
- $u$: Target page
- $B_u$: Set of pages that link to page $u$
- $L(v)$: Number of outbound internal links on page $v$
- $d$: Damping factor (typically set to 0.85)
┌─────────────────────────────────────────────────────────────┐
│ INTERNAL PAGERANK LINK GRAPH │
└─────────────────────────────────────────────────────────────┘
[Homepage]
(PR Score: 1.0)
│ │
┌────────────┘ └────────────┐
▼ ▼
[/features] [/pricing]
(PR Score: 0.42) (PR Score: 0.38)
│ │ │
▼ ▼ ▼
[/crm-ai] [/visual-cro] [Checkout]
(PR: 0.18) (PR: 0.16) (PR: 0.22)
2. Programmatic Graph Traversal in TypeScript
Here is how Plyxo calculates click depth and detects orphan pages:
export interface PageNode {
url: string;
inboundLinks: Set<string>;
outboundLinks: Set<string>;
clickDepth: number;
}
export function buildLinkGraph(crawlResults: Array<{ url: string; links: string[] }>) {
const graph = new Map<string, PageNode>();
// Initialize nodes
for (const { url } of crawlResults) {
graph.set(url, {
url,
inboundLinks: new Set(),
outboundLinks: new Set(),
clickDepth: Infinity,
});
}
// Populate graph edges
for (const { url, links } of crawlResults) {
const sourceNode = graph.get(url)!;
for (const link of links) {
if (graph.has(link)) {
sourceNode.outboundLinks.add(link);
graph.get(link)!.inboundLinks.add(url);
}
}
}
// Compute Breadth-First Search (BFS) click depth starting from root '/'
const queue: Array<{ url: string; depth: number }> = [{ url: '/', depth: 0 }];
const visited = new Set<string>(['/']);
while (queue.length > 0) {
const { url, depth } = queue.shift()!;
const node = graph.get(url);
if (node) {
node.clickDepth = Math.min(node.clickDepth, depth);
for (const outbound of node.outboundLinks) {
if (!visited.has(outbound)) {
visited.add(outbound);
queue.push({ url: outbound, depth: depth + 1 });
}
}
}
}
// Identify orphan pages (0 inbound links) and deep pages (depth > 3)
const orphans = Array.from(graph.values()).filter(n => n.inboundLinks.size === 0 && n.url !== '/');
const deepPages = Array.from(graph.values()).filter(n => n.clickDepth > 3);
return { graph, orphans, deepPages };
}
3. Actionable Fixes to Optimize Link Equity
- Keep Critical Pages Under 3 Clicks: Every revenue-generating page should have a click depth $\le 3$ from the root homepage.
- Footer & Navigation Siloing: Group related topic clusters in your footer and sub-navigation menus so crawlers follow structured pathways.
- Eliminate Dead-End Pages: Ensure every documentation page includes "Next Steps" or related links to prevent search bot crawl termination.
Top comments (0)