
Orphan Pages Internal Linking Opportunities
- 77 installs
- 93 repo stars
- Updated June 28, 2026
- infrasity-labs/dev-gtm-claude-skills
orphan-pages-internal-linking-opportunities is a workflow skill that audits a site’s content section for orphan pages—URLs no other page links to—and turns each gap into actionable internal links.
About
orphan-pages-internal-linking-opportunities is a workflow skill that audits a site’s content section for orphan pages—URLs no other page links to—and turns each gap into actionable internal links. It pulls the content inventory from your sitemap, uses Ahrefs to see which posts lack inbound internal links, clusters orphans by topic, and produces three concrete suggestions per page: suggested source URL, anchor text, where to place the link, and a sentence ready to paste into the CMS. The deliverable is a styled HTML report you can filter and hand to a client or content teammate. Solo builders with blogs, docs, or developer marketing sites use it after publishing velocity outpaces navigation design. It does not replace a full technical SEO platform but closes a specific structural hole that wastes pages search engines never find through internal crawl.
- Discovers content URLs via sitemap and flags zero incoming internal links (Ahrefs)
- Clusters orphan pages by topic and derives keywords per URL
- Generates 3 linking suggestions per orphan with anchor text, placement, and copy-paste context
- Outputs a styled filterable HTML report for client or team delivery
- Built for SEO, content, and dev-marketing teams fixing navigation gaps in growing libraries
Orphan Pages Internal Linking Opportunities by the numbers
- 77 all-time installs (skills.sh)
- +5 installs in the week ending Jul 25, 2026 (Skillselion tracking)
- Ranked #1,194 of 1,881 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Jul 26, 2026 (Skillselion catalog sync)
npx skills add https://github.com/infrasity-labs/dev-gtm-claude-skills --skill orphan-pages-internal-linking-opportunitiesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 77 |
|---|---|
| repo stars | ★ 93 |
| Last updated | June 28, 2026 |
| Repository | infrasity-labs/dev-gtm-claude-skills ↗ |
How do I find blog and content URLs with zero internal links and get three paste-ready linking suggestions per orphan in an HTML audit report.?
Find blog and content URLs with zero internal links and get three paste-ready linking suggestions per orphan in an HTML audit report.
Who is it for?
Best when you're working on marketing & seo and need structured help with orphan pages internal linking opportunities.
Skip if: Teams with no marketing & seo needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to find blog and content URLs with zero internal links and get three paste-ready linking suggestions per orphan in an HTML audit report., or when orphan-pages-internal-linking-opportunities is a workflow sk
What you get
Structured output aligned to orphan-pages-internal-linking-opportunities: Discovers content URLs via sitemap and flags zero incoming internal links (Ahrefs), Clusters orphan pages by topic and derives keywords per URL.
Files
Orphan Page Audit & Interlinking Brief Generator
You are running a complete SEO orphan page audit. The user has provided a domain as input via args. Your job is to execute every phase below in order, using the tools available, and produce a single downloadable HTML report file saved to the current working directory.
Input domain: {args}
---
PHASE 1 — Domain Normalization & Sitemap Discovery
1. Normalize the input domain:
- Strip leading/trailing whitespace
- If it doesn't start with
http, prependhttps:// - If it doesn't have
www.and the base domain resolves with it, usewww. - Remove any trailing slash
- Store as
BASE_URL(e.g.,https://www.example.com)
2. Fetch BASE_URL/robots.txt using WebFetch. Look for any Sitemap: directive — if found, use that URL as the sitemap location. If not found, default to BASE_URL/sitemap.xml.
3. Fetch the sitemap URL. Determine its type:
- Sitemap index (
<sitemapindex>tag present): extract all<loc>child sitemap URLs, fetch each one, and merge all<loc>URLs from every child sitemap into a single master URL list - Regular sitemap (
<urlset>tag): extract all<loc>URLs directly
4. Store the full master URL list.
---
PHASE 2 — Blog URL Identification
From the master URL list:
1. Analyze all URL patterns to identify the blog/content section. Look for the URL prefix that appears most frequently in a uniform pattern. Common prefixes to check: /blog/, /articles/, /posts/, /insights/, /resources/, /learn/, /news/, /guides/
2. Select the prefix that best represents the blog content (most URLs, most uniform structure). If multiple prefixes qualify, include all of them.
3. Filter the master URL list to only include URLs matching the identified blog prefix(es). Exclude index/listing pages (e.g., BASE_URL/blog with no further slug). Store as BLOG_URLS.
4. If no blog prefix is identifiable from the sitemap, fetch BASE_URL homepage and look for a blog/articles navigation link, then fetch that page and extract all post URLs from it.
5. Log the total count: "Found {N} blog posts at {BASE_URL}"
---
PHASE 3 — Crawl & Build Inbound Link Map
Run a Workflow to crawl all blog posts in parallel. The workflow should:
Script logic:
- Take
BLOG_URLSas the items list - For each URL, spawn an agent that:
- Fetches the page using WebFetch
- Extracts ALL href links in the body/article content (not nav, header, footer) that point to other pages on the same domain matching the blog URL pattern
- Normalizes all found links to absolute URLs (no trailing slash, no query params, no hash)
- Returns
{ source_url, outbound_blog_links: [...] } - Use schema:
{ type: 'object', properties: { source_url: { type: 'string' }, outbound_blog_links: { type: 'array', items: { type: 'string' } } }, required: ['source_url', 'outbound_blog_links'] }
After the workflow completes, aggregate results:
- Build
inbound_countmap:{ url -> number }initialized to 0 for allBLOG_URLS - Build
inbound_sourcesmap:{ url -> [source_url, ...] }initialized to[]for allBLOG_URLS - For each crawl result, iterate
outbound_blog_linksand increment the inbound count + push the source URL for each valid link
Classify every page:
- Orphan = 0 inbound links → store as
ORPHAN_URLS - Low-linked = 1–2 inbound links → store as
LOW_LINKED_URLS - Healthy = 3+ inbound links → store as
HEALTHY_URLS
Build FULL_INBOUND_MAP: array of { url, inbound, linked_from } sorted descending by inbound count.
---
PHASE 4 — Keyword Research for Orphan Pages
Run a Workflow to get the top US search volume keyword for each orphan page. The workflow should:
Script logic:
- Take
ORPHAN_URLSas the items list - For each orphan URL, spawn an agent that:
1. Extracts the slug from the URL (last path segment) 2. Generates 6–8 keyword variants from the slug (convert hyphens to spaces, try variations with different word orders, add/remove qualifiers) 3. Uses ToolSearch to load mcp__claude_ai_DataForSEO__kw_data_google_ads_search_volume, then calls it with the keyword variants, location_code: 2840 (United States), language_code: "en" 4. Picks the keyword with the highest US monthly search volume as anchor_text 5. Fallback: if DataForSEO returns no data or errors, convert the slug to a phrase (hyphens → spaces) as the anchor_text 6. Fetches the page and writes a 2–3 sentence page_summary of what the page covers 7. Returns { orphan_url, anchor_text, us_monthly_volume, page_summary }
- Use schema:
{ type: 'object', properties: { orphan_url: { type: 'string' }, anchor_text: { type: 'string' }, us_monthly_volume: { type: 'number' }, page_summary: { type: 'string' } }, required: ['orphan_url', 'anchor_text', 'us_monthly_volume', 'page_summary'] }
Store results as KEYWORD_DATA: map of { orphan_url -> { anchor_text, us_monthly_volume, page_summary } }
---
PHASE 5 — Generate Interlinking Briefs for Orphan Pages
Run a Workflow using a 2-stage pipeline over ORPHAN_URLS:
Stage 1 — Pass through keyword data (already computed, no agent needed — use the KEYWORD_DATA directly)
Stage 2 — For each orphan, spawn an agent that: 1. Receives orphan_url, anchor_text, page_summary, and the full BLOG_URLS list 2. Selects exactly 3 topically relevant source pages from BLOG_URLS (exclude the orphan itself; prefer well-linked, non-orphan pages) 3. Fetches each of the 3 source pages using WebFetch 4. For each source page produces:
source_url: the full URL of the source pagewhere_to_place: specific, precise description of the location within that page — naming the H2/H3 section, which paragraph, what content surrounds it. Must be specific enough that a content editor can navigate there without guessingcontext_copy: minimum 300 characters of naturally flowing copy to be inserted at that location. Theanchor_textMUST appear exactly once within it as<a href="ORPHAN_URL">ANCHOR_TEXT</a>. Copy must read as if it was always part of the article — not promotional, not forced. Same anchor text across all 3 placements.
5. Returns { orphan_url, anchor_text, placements: [{ source_url, where_to_place, context_copy }, ...] }
- Use schema with
placementsas array of 3 objects each requiringsource_url,where_to_place,context_copy
After the workflow completes, post-process every context_copy:
- Check if
anchor_textappears as a hyperlink (href="orphan_url"present) - If not, find the first occurrence of
anchor_text(case-insensitive) and replace with<a href="orphan_url">anchor_text</a>
Store as BRIEFS.
---
PHASE 6 — Generate HTML Report
Using the Write tool, save a single self-contained HTML file to the current working directory named orphan-audit-{domain}-{YYYYMMDD}.html where {domain} is the base domain (no protocol, no www, dots replaced with hyphens) and {YYYYMMDD} is today's date.
The HTML file must be completely self-contained — all CSS inline in a <style> tag, no external CDN or font imports, works offline. Use clean, professional design with the following structure:
HTML Report Structure
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Orphan Page Audit — {domain}</title>
<style>
/* Full inline CSS — professional design, light background, clean typography */
/* Use system fonts: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif */
/* Color palette: #0f172a (headings), #334155 (body), #3b82f6 (accent/links), #f1f5f9 (backgrounds), #e2e8f0 (borders) */
/* Stat cards, tables, collapsible sections, copy buttons */
</style>
</head>
<body>Section 1 — Header
- Site logo area with domain name (large)
- Audit date
- "Download Report" button (triggers
window.print()or direct file save)
Section 2 — Executive Summary Four stat cards in a row:
- Total Blog Posts Found:
{BLOG_URLS.length} - Orphan Pages:
{ORPHAN_URLS.length}+ percentage of total - Low-Linked Pages:
{LOW_LINKED_URLS.length}(1–2 inbound links) - Healthy Pages:
{HEALTHY_URLS.length}(3+ inbound links)
A horizontal bar showing the proportion of orphan / low-linked / healthy visually.
Section 3 — Orphan Pages List Table with columns: # | Page URL (clickable link) | Anchor Text | US Monthly Volume One row per orphan page.
Section 4 — Inbound Link Map (Non-Orphan Pages) Table sorted descending by inbound count: Page URL | Inbound Links | Linked From For the "Linked From" column, list each source URL on a new line or as a comma-separated list.
Section 5 — Interlinking Briefs For each orphan page, a card containing:
- Orphan URL (h3, clickable)
- Anchor Text (badge/pill)
- US Monthly Search Volume
- Three placement blocks, each showing:
- Source page URL (bold, clickable)
- "Where to Place" — displayed as a styled blockquote or info box
- "Context Copy" — displayed in a styled
<pre>or<div>with a "Copy" button that usesnavigator.clipboard.writeText()to copy the HTML
Section 6 — Footer
- "Generated by Infrasity Orphan Page Audit Skill"
- Audit date and domain
JavaScript (inline <script> tag)
- Copy button functionality:
navigator.clipboard.writeText(element.innerText) - Smooth scroll for any nav links
- Optional: collapse/expand for brief cards
---
PHASE 7 — Confirm & Report to User
After saving the HTML file: 1. Report the file path to the user 2. Give a brief summary:
- Total blog posts found
- Number of orphan pages
- Number of interlinking briefs generated
- File name and location
3. Note any pages where keyword data could not be fetched from DataForSEO (fell back to slug)
---
Important Rules
- Never hardcode `/blog/` — always detect the URL pattern from the actual sitemap
- Anchor text is fixed per orphan — the same
anchor_textstring appears in all 3context_copyblocks for that orphan, always as a hyperlink - Context copy minimum 300 characters — enforce strictly; if an agent returns shorter copy, flag it
- Where to place must be specific — section heading + paragraph position + surrounding content context
- HTML report is self-contained — no external requests, no CDN, works offline
- DataForSEO fallback — if API returns no data, use the slug converted to a readable phrase
- Post-process hyperlinks — after all briefs are generated, always verify and fix anchor text hyperlinks before writing the HTML
- File naming —
orphan-audit-{domain}-{YYYYMMDD}.htmlsaved in the user's current working directory
Orphan Pages: Internal Linking Opportunities
Discovers every blog or content page that receives zero incoming internal links, clusters them by topic, and generates 3 specific linking suggestions per orphan, with exact anchor text, placement guidance, and ready-to-paste context copy. Outputs a styled, filterable HTML report.
---
What this skill does
An orphan page is a page that no other page on the site links to. It cannot be discovered through normal navigation and is invisible to crawlers following internal links. This audit finds every orphan in a content section and recommends exactly which existing pages should link to each one.
The skill discovers all content pages via sitemap, identifies which have incoming links using Ahrefs, derives keywords for each orphan, clusters pages by topic, and generates 3 fully formed linking suggestions per orphan, including the anchor text to use, where in the source page to place the link, and a sentence ready to copy and paste.
Built for:
- SEO and content teams finding pages that are being published but never surfaced through navigation
- Developer marketing fixing structural link gaps across a growing content library
- Agencies delivering an internal linking audit as a client deliverable
---
Installation
Claude Code (Recommended)
Clone the repo. The skill activates automatically when you open it in Claude Code:
git clone https://github.com/Infrasity-Labs/dev-gtm-claude-skills.git
cd dev-gtm-claude-skills
claudeThen trigger it with:
/dev-gtm orphan-pages example.com/blog/Or describe what you want. Claude activates the skill when you provide a domain and ask for an orphan page audit or internal linking report.
Claude Web (Free / Pro)
1. Go to [Settings → Capabilities](https://claude.ai/settings/capabilities) and enable Code execution and file creation 2. Go to [Customize → Skills](https://claude.ai/customize/skills) 3. Click + → Create skill → Upload a skill 4. Zip this skill folder and upload it:
cd dev-gtm-claude-skills/skills/orphan-pages-internal-linking-opportunities
zip -r ../orphan-pages-internal-linking-opportunities.zip .Upload orphan-pages-internal-linking-opportunities.zip and toggle it on.
---
Ahrefs Setup (Required)
This skill uses two Ahrefs tools to identify orphan pages and fetch keyword data. An active Ahrefs account with API access is required.
Claude Code
Open .claude/settings.json in the cloned repo and add your Ahrefs MCP credentials:
{
"mcpServers": {
"Ahrefs": {
"command": "npx",
"args": ["-y", "@ahrefs/mcp-server"],
"env": {
"AHREFS_API_KEY": "your-ahrefs-api-key"
}
}
}
}Claude Web (Free / Pro)
Go to [Settings → Integrations](https://claude.ai/settings/integrations), find Ahrefs, and connect your account.
---
How to use
Run an orphan page audit for example.comWhich pages on example.com/blog/ have no internal links?Find pages nobody links to on my site/dev-gtm orphan-pages example.com/blog/If the content section prefix (/blog/, /articles/, etc.) is not clear from the input, Claude asks before starting.
---
Inputs
| Field | Required | Notes |
|---|---|---|
| Domain or URL | ✅ | Domain (example.com), full URL, sitemap URL, or blog prefix URL |
| Content prefix | ⬜ | Optional. If not provided and not inferrable from the URL, Claude asks |
---
Output
A self-contained filterable HTML report saved to /mnt/user-data/outputs/[domain]-orphan-linking-audit.html and presented with a download link.
The report contains:
- Header stats: Total Pages, Orphan Count, Pages With Links, Gap Rate %, Total Suggestions
- Cluster sidebar: topic clusters built automatically from the orphan set, clickable for filtering
- Search and filter bar: live search across all orphan titles and keywords
- Per-orphan cards: title, URL, top keyword, monthly traffic, cluster tag
- 3 suggestions per orphan: Source page, anchor text, where to place it, and ready-to-paste context copy with the link already embedded as an HTML
<a>tag
---
Things to know
Ahrefs is queried site-wide with no source URL filter. The site-explorer-pages-by-internal-links call is intentionally run without a url_from filter. Filtering by source prefix misses links from the homepage, service pages, and navigation, producing false orphans. The fix-tag in the report footer records this.
Keyword data may be absent for newer pages. When a page has no Ahrefs ranking data, the skill derives its primary keyword from the URL slug (/blog/developer-marketing-strategy → "developer marketing strategy"). This is noted in the report.
Suggestions are topically justified, not generic. Every suggestion is chosen because the source page covers the same or adjacent subject matter. "Link from your homepage" is never suggested unless the homepage genuinely relates to the orphan's topic.
JS-rendered sites cannot be crawled by curl. If the sitemap is empty or the blog index returns no URLs from curl, the skill will ask for a static sitemap export or a manual URL list.
---
How it works
1. Discover content pages: finds the sitemap via curl (tries /sitemap.xml, /sitemap_index.xml, robots.txt), extracts all <loc> URLs, filters to the content prefix, and strips pagination, category, and tag pages 2. Identify orphans: calls Ahrefs:site-explorer-pages-by-internal-links site-wide (no url_from filter) to get all pages with at least one incoming link; anything in the full URL list but not in this result is an orphan 3. Fetch keyword data: calls Ahrefs:site-explorer-top-pages for the full content prefix to get the top keyword and monthly traffic for every page in one call 4. Derive missing keywords: for any orphan not in the Ahrefs response, derives the primary keyword from the URL slug 5. Cluster by topic: groups orphans into 5–15 topic clusters adapted to the site's actual content 6. Generate suggestions: for each orphan, identifies 3 topically related pages from the full URL list and writes anchor text, placement guidance, and a ready-to-paste context copy sentence for each 7. Generate the HTML report: reads references/report-style-reference.html and builds a fully data-driven report by populating the CC{} (cluster colour map) and D[] (orphan data) JavaScript objects; the sidebar builder and filterAll() function render all cards from this data
---
Config schema reference
The JavaScript data objects injected into the HTML report:
// Cluster colour map
const CC = {
"Developer Marketing": "c-devmkt",
"SEO": "c-seo",
"Content Marketing": "c-content",
"Documentation": "c-docs",
"GTM Strategy": "c-gtm"
};
// Orphan page data: one object per orphan
const D = [
{
url: "https://www.example.com/blog/developer-marketing-strategy",
title: "Developer Marketing Strategy: A Complete Guide",
kw: "developer marketing strategy",
tr: null,
cluster: "Developer Marketing",
s: [
{
from: "How to Build a Developer Community",
fromUrl: "https://www.example.com/blog/build-developer-community",
anchor: "developer marketing strategy",
place: "In the intro when explaining why community building is part of a broader go-to-market plan",
copy: "Before diving into community tactics, it helps to understand how they fit into a wider <a href=\"https://www.example.com/blog/developer-marketing-strategy\">developer marketing strategy</a>, especially if you are building from scratch."
}
// × 3 per orphan
]
}
];---
File structure
orphan-pages-internal-linking-opportunities/
├── SKILL.md # Skill instructions Claude follows
├── README.md # This file
└── references/
└── report-style-reference.html # Canonical visual and code reference for the HTML report<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Orphan Page Audit — Design Reference</title>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<!--
══════════════════════════════════════════════════════════════════════
DESIGN REFERENCE — Orphan Page / Internal Linking Audit Report
══════════════════════════════════════════════════════════════════════
This file is the single source of truth for every report generated
by the orphan-pages-internal-linking-opportunities skill.
HOW TO USE THIS FILE
────────────────────
1. Copy CSS variables from :root — never substitute different values.
2. Copy component HTML patterns from the annotated examples below.
3. Copy JavaScript patterns (filterAll, sidebar, toggle) verbatim.
4. Replace placeholder content with real audit data.
5. Do not add new CSS classes or modify existing values.
SECTIONS IN THIS FILE
─────────────────────
A. CSS Design Tokens (:root variables)
B. Full Stylesheet (all component styles)
C. Component Catalogue (annotated HTML examples of every component)
C1. Header
C2. Controls Bar
C3. Layout (sidebar + content)
C4. Sidebar Link
C5. Cluster Section Header
C6. Blog Card — Collapsed
C7. Blog Card — Expanded (Suggestions Panel)
C8. Cluster Tags
C9. Footer
C10. No-Results State
D. JavaScript Reference (filterAll, sidebar build, toggle)
══════════════════════════════════════════════════════════════════════
-->
<style>
/* ══════════════════════════════════════════════════════
A. DESIGN TOKENS — copy :root verbatim into every report
══════════════════════════════════════════════════════ */
:root {
--bg: #0a0a0b;
--surface: #111113;
--surface2: #18181c;
--tag-bg: #1e1e28;
--border: #27272e;
--border2: #35353f;
--text: #e8e8f0;
--text2: #9090a8;
--text3: #5a5a72;
--pass: #22c55e;
--pass-bg: #0d2b1a;
--pass-border: #14532d;
--warn: #f59e0b;
--warn-bg: #2b1f06;
--warn-border: #78350f;
--fail: #ef4444;
--fail-bg: #2b0a0a;
--fail-border: #7f1d1d;
--accent: #6366f1;
--accent2: #818cf8;
}
/* ══════════════════════════════════════════════════════
B. FULL STYLESHEET
══════════════════════════════════════════════════════ */
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:'IBM Plex Sans',sans-serif;font-size:14px;line-height:1.6;min-height:100vh}
/* HEADER */
.header{border-bottom:1px solid var(--border);padding:48px 64px 40px;background:linear-gradient(180deg,#0f0f18 0%,var(--bg) 100%);position:relative;overflow:hidden}
.header::before{content:'';position:absolute;top:-60px;left:-60px;width:300px;height:300px;background:radial-gradient(circle,rgba(99,102,241,.12) 0%,transparent 70%);pointer-events:none}
.header-meta{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--accent2);letter-spacing:.12em;text-transform:uppercase;margin-bottom:12px}
.header h1{font-size:32px;font-weight:600;letter-spacing:-.02em;color:var(--text);margin-bottom:8px}
.header-url{font-family:'IBM Plex Mono',monospace;font-size:13px;color:var(--text2);background:var(--surface2);border:1px solid var(--border);display:inline-block;padding:6px 14px;border-radius:4px;margin-bottom:32px}
.header-stats{display:flex;gap:32px;flex-wrap:wrap}
.hstat{display:flex;flex-direction:column;gap:4px}
.hstat-val{font-family:'IBM Plex Mono',monospace;font-size:28px;font-weight:600;line-height:1}
.hstat-val.total{color:var(--text)}.hstat-val.fail{color:var(--fail)}.hstat-val.pass{color:var(--pass)}.hstat-val.warn{color:var(--warn)}.hstat-val.accent{color:var(--accent2)}
.hstat-label{font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:.1em}
.stat-divider{width:1px;background:var(--border);align-self:stretch;margin:4px 0}
.fix-tag{margin-top:20px;display:inline-flex;align-items:center;gap:8px;background:var(--warn-bg);border:1px solid var(--warn-border);padding:6px 14px;border-radius:4px;font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--warn)}
/* CONTROLS BAR */
.controls{background:var(--surface);border-bottom:1px solid var(--border);padding:14px 64px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;position:sticky;top:0;z-index:100}
.search-wrap{position:relative;flex:1;min-width:220px}
.search-wrap svg{position:absolute;left:11px;top:50%;transform:translateY(-50%);opacity:.4}
input[type=text]{width:100%;background:var(--bg);border:1px solid var(--border);color:var(--text);font-family:'IBM Plex Mono',monospace;font-size:12px;padding:8px 11px 8px 34px;border-radius:4px;outline:none;transition:border-color .15s}
input[type=text]:focus{border-color:var(--accent)}
input[type=text]::placeholder{color:var(--text3)}
select{background:var(--bg);border:1px solid var(--border);color:var(--text2);font-family:'IBM Plex Mono',monospace;font-size:12px;padding:8px 12px;border-radius:4px;outline:none;cursor:pointer}
.result-count{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text3)}
.result-count strong{color:var(--fail)}
/* LAYOUT */
.main{display:grid;grid-template-columns:240px 1fr;min-height:calc(100vh - 220px)}
/* SIDEBAR */
.sidebar{border-right:1px solid var(--border);padding:24px 0;position:sticky;top:57px;height:calc(100vh - 57px);overflow-y:auto}
.sidebar::-webkit-scrollbar{width:4px}
.sidebar::-webkit-scrollbar-track{background:transparent}
.sidebar::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}
.sidebar-heading{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text3);text-transform:uppercase;letter-spacing:.15em;padding:8px 20px 4px}
.sidebar-link{display:flex;align-items:center;justify-content:space-between;padding:7px 20px;color:var(--text2);text-decoration:none;font-size:12px;cursor:pointer;transition:all .15s;border-left:2px solid transparent}
.sidebar-link:hover{background:var(--surface2);color:var(--text);border-left-color:var(--border2)}
.sidebar-link.active{background:var(--surface2);color:var(--text);border-left-color:var(--accent)}
.sc{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text3)}
/* CONTENT */
.content{padding:40px 56px;max-width:1200px}
/* CLUSTER SECTION */
.cluster-section{margin-bottom:64px;scroll-margin-top:70px}
.cluster-header{display:flex;align-items:center;gap:12px;margin-bottom:20px;padding-bottom:14px;border-bottom:1px solid var(--border)}
.cluster-title{font-size:18px;font-weight:600;letter-spacing:-.01em}
.cluster-badge{font-family:'IBM Plex Mono',monospace;font-size:11px;padding:3px 10px;border-radius:20px;border:1px solid var(--border2);color:var(--text3)}
.section-label{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--accent2);text-transform:uppercase;letter-spacing:.15em;margin-bottom:14px}
/* BLOG CARD */
.blog-card{border:1px solid var(--border);border-radius:6px;margin-bottom:10px;overflow:hidden;transition:border-color .15s}
.blog-card:hover{border-color:var(--border2)}
.blog-card.hidden{display:none}
.blog-header{display:flex;align-items:stretch;background:var(--surface);cursor:pointer;user-select:none}
.blog-header:hover{background:var(--surface2)}
.blog-title-col{padding:14px 18px;flex:1;min-width:0}
.blog-name{font-size:13px;font-weight:500;color:var(--text);margin-bottom:3px;line-height:1.35}
.blog-url{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--accent2);text-decoration:none;opacity:.8}
.blog-url:hover{opacity:1;text-decoration:underline}
.blog-kw-col{padding:14px 16px;border-left:1px solid var(--border);min-width:170px;display:flex;flex-direction:column;gap:4px;justify-content:center}
.kw-pill{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text2);background:var(--tag-bg);border:1px solid var(--border2);padding:2px 8px;border-radius:3px;display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:150px}
.kw-traffic{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text3)}
.kw-traffic.hot{color:var(--pass)}
.blog-cluster-col{padding:14px;border-left:1px solid var(--border);display:flex;align-items:center;justify-content:center;min-width:130px}
.chevron{color:var(--text3);font-size:9px;transition:transform .2s;padding:14px;display:flex;align-items:center;border-left:1px solid var(--border)}
.blog-card.open .chevron{transform:rotate(180deg)}
/* SUGGESTIONS PANEL */
.blog-body{display:none;border-top:1px solid var(--border);background:var(--bg)}
.blog-card.open .blog-body{display:block}
.sug-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--border)}
.sug-cell{background:var(--bg);padding:16px 18px}
.sug-num{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text3);margin-bottom:8px;text-transform:uppercase;letter-spacing:.1em}
.sug-from-title{font-size:12px;font-weight:500;color:var(--text);margin-bottom:4px;line-height:1.35}
.sug-from-url{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--accent2);text-decoration:none;opacity:.75;display:inline-block;margin-bottom:10px;word-break:break-all}
.sug-from-url:hover{opacity:1;text-decoration:underline}
.sug-divider{height:1px;background:var(--border);margin:8px 0}
.sug-anchor-label{font-family:'IBM Plex Mono',monospace;font-size:9px;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:4px}
.sug-anchor{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--pass);background:var(--pass-bg);border:1px solid var(--pass-border);padding:3px 8px;border-radius:3px;display:inline-block;margin-bottom:10px}
.sug-place-label{font-family:'IBM Plex Mono',monospace;font-size:9px;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:4px}
.sug-place{font-size:12px;color:var(--text2);line-height:1.5}
.sug-copy{font-size:12px;color:var(--text2);line-height:1.6;background:var(--surface2);border-left:2px solid var(--accent2);padding:7px 10px;border-radius:0 3px 3px 0;margin-top:2px}.sug-copy a{color:var(--accent2);text-decoration:underline}
/* CLUSTER TAGS */
.ctag{font-family:'IBM Plex Mono',monospace;font-size:10px;padding:3px 9px;border-radius:3px;border:1px solid;white-space:nowrap;letter-spacing:.03em}
.c-reddit {color:#fb923c;border-color:rgba(251,146,60,.3);background:rgba(251,146,60,.07)}
.c-devmkt {color:#60a5fa;border-color:rgba(96,165,250,.3);background:rgba(96,165,250,.07)}
.c-content {color:#a78bfa;border-color:rgba(167,139,250,.3);background:rgba(167,139,250,.07)}
.c-seo {color:#f472b6;border-color:rgba(244,114,182,.3);background:rgba(244,114,182,.07)}
.c-docs {color:#34d399;border-color:rgba(52,211,153,.3);background:rgba(52,211,153,.07)}
.c-llm {color:#fbbf24;border-color:rgba(251,191,36,.3);background:rgba(251,191,36,.07)}
.c-gtm {color:#fb7185;border-color:rgba(251,113,133,.3);background:rgba(251,113,133,.07)}
.c-devrel {color:#2dd4bf;border-color:rgba(45,212,191,.3);background:rgba(45,212,191,.07)}
.c-techwrite{color:#67e8f9;border-color:rgba(103,232,249,.3);background:rgba(103,232,249,.07)}
.c-product {color:#fda4af;border-color:rgba(253,164,175,.3);background:rgba(253,164,175,.07)}
.c-other {color:#94a3b8;border-color:rgba(148,163,184,.3);background:rgba(148,163,184,.07)}
/* NO RESULTS */
.no-results{text-align:center;padding:80px;color:var(--text3);font-family:'IBM Plex Mono',monospace;display:none}
.no-results strong{color:var(--text2);display:block;font-size:16px;margin-bottom:8px}
/* FOOTER */
footer{border-top:1px solid var(--border);padding:20px 64px;display:flex;justify-content:space-between;font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text3)}
/* RESPONSIVE */
@media(max-width:900px){
.main{grid-template-columns:1fr}
.sidebar{display:none}
.header,.controls,.content{padding-left:20px;padding-right:20px}
.sug-grid{grid-template-columns:1fr}
}
</style>
</head>
<body>
<!--
══════════════════════════════════════════════════════════════════════
C. COMPONENT CATALOGUE
Each section shows the exact HTML pattern to copy into a real report.
Replace all placeholder text/values with real audit data.
══════════════════════════════════════════════════════════════════════
-->
<!-- C1. HEADER ─────────────────────────────────────── -->
<div class="header">
<div class="header-meta">Internal Linking Audit Report · example.com</div>
<h1>Orphan Blog Post Audit</h1>
<div class="header-url">https://www.example.com/blog/</div>
<div class="header-stats">
<!-- Stat order: Total · divider · Fail · Pass · divider · Warn · Accent -->
<div class="hstat"><span class="hstat-val total">136</span><span class="hstat-label">Total Blogs</span></div>
<div class="stat-divider"></div>
<div class="hstat"><span class="hstat-val fail">84</span><span class="hstat-label">Zero Incoming Links</span></div>
<div class="hstat"><span class="hstat-val pass">52</span><span class="hstat-label">Have Links</span></div>
<div class="stat-divider"></div>
<div class="hstat"><span class="hstat-val warn">62%</span><span class="hstat-label">Gap Rate</span></div>
<div class="hstat"><span class="hstat-val accent">252</span><span class="hstat-label">Suggestions</span></div>
</div>
<!-- Method/version note — always include below stats -->
<div class="fix-tag">⚑ Ahrefs site-wide query (no url_from filter) · May 27 2026</div>
</div>
<!-- C2. CONTROLS BAR ───────────────────────────────── -->
<div class="controls">
<div class="search-wrap">
<svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
<input type="text" id="searchInput" placeholder="Search title, URL or keyword…" oninput="filterAll()">
</div>
<select id="clusterFilter" onchange="filterAll()">
<option value="">All Clusters</option>
<option>Reddit Marketing</option>
<option>Developer Marketing</option>
<option>Content Marketing</option>
<option>SEO</option>
<option>Documentation</option>
<option>LLM / AI Visibility</option>
<option>GTM Strategy</option>
<option>DevRel</option>
<option>Technical Writing</option>
<option>Product</option>
<option>Other</option>
</select>
<span class="result-count">Showing <strong id="vc">1</strong> of 1</span>
</div>
<!-- C3. LAYOUT ─────────────────────────────────────── -->
<div class="main">
<!-- C4. SIDEBAR — shell; JS builds links inside -->
<nav class="sidebar" id="sidebar">
<!--
JS inserts:
<div class="sidebar-heading">Clusters</div>
<div class="sidebar-link active">
<span>All Clusters</span><span class="sc">84</span>
</div>
<div class="sidebar-link">
<span>Reddit Marketing</span><span class="sc">12</span>
</div>
… one per cluster
-->
</nav>
<div class="content" id="content">
<!-- C10. NO RESULTS STATE -->
<div class="no-results" id="noResults">
<strong>No results found</strong>
Try a different search or cluster filter
</div>
<!-- C5. CLUSTER SECTION HEADER
id = "sec-" + cluster name kebab-cased
e.g. "Reddit Marketing" → id="sec-Reddit-Marketing" -->
<div class="cluster-section" id="sec-Reddit-Marketing">
<div class="cluster-header">
<div class="cluster-title">Reddit Marketing</div>
<span class="cluster-badge">12 blogs</span>
</div>
<!-- C6. BLOG CARD — COLLAPSED
data-title, data-url, data-kw, data-cluster drive search/filter -->
<div class="blog-card"
data-title="karma farming vs credibility on reddit"
data-url="reddit-karma-farming-vs-credibility"
data-kw="reddit karma farming"
data-cluster="Reddit Marketing">
<div class="blog-header" onclick="this.closest('.blog-card').classList.toggle('open')">
<!-- Column 1: title + URL -->
<div class="blog-title-col">
<div class="blog-name">Karma Farming vs Credibility on Reddit</div>
<a class="blog-url"
href="https://www.example.com/blog/reddit-karma-farming-vs-credibility"
target="_blank"
onclick="event.stopPropagation()">
example.com/blog/reddit-karma-farming-vs-credibility
</a>
</div>
<!-- Column 2: keyword + traffic
Rules:
null → <span class="kw-traffic">—</span>
≥10 /mo → <span class="kw-traffic hot">▲ N visits/mo</span>
1-9 /mo → <span class="kw-traffic">▲ N visits/mo</span>
0 traffic → <span class="kw-traffic">ranking · 0 traffic</span>
-->
<div class="blog-kw-col">
<span class="kw-pill">reddit karma farming</span>
<span class="kw-traffic">—</span>
</div>
<!-- Column 3: cluster tag -->
<div class="blog-cluster-col">
<span class="ctag c-reddit">Reddit Marketing</span>
</div>
<!-- Column 4: chevron -->
<div class="chevron">▼</div>
</div>
<!-- C7. SUGGESTIONS PANEL — EXPANDED
Always exactly 3 .sug-cell columns.
Both target URL (blog-url) and all source URLs (sug-from-url)
must be clickable <a href> links opening target="_blank". -->
<div class="blog-body">
<div class="sug-grid">
<div class="sug-cell">
<div class="sug-num">Suggestion 1</div>
<div class="sug-from-title">Dos and Don'ts of Reddit Marketing</div>
<a class="sug-from-url" href="https://www.example.com/blog/reddit-marketing" target="_blank">example.com/blog/reddit-marketing</a>
<div class="sug-divider"></div>
<div class="sug-anchor-label">Anchor Text</div>
<div class="sug-anchor">"karma farming on Reddit"</div>
<div class="sug-place-label">Where to Place</div>
<div class="sug-place">In the 'What to Avoid' section when listing bad Reddit practices</div>
</div>
<div class="sug-cell">
<div class="sug-num">Suggestion 2</div>
<div class="sug-from-title">Best Subreddits to Join for B2B SaaS Startups</div>
<a class="sug-from-url" href="https://www.example.com/blog/best-subreddits" target="_blank">example.com/blog/best-subreddits</a>
<div class="sug-divider"></div>
<div class="sug-anchor-label">Anchor Text</div>
<div class="sug-anchor">"karma vs credibility debate"</div>
<div class="sug-place-label">Where to Place</div>
<div class="sug-place">In the intro when explaining why genuine participation matters</div>
</div>
<div class="sug-cell">
<div class="sug-num">Suggestion 3</div>
<div class="sug-from-title">How Do You Get Karma on Reddit</div>
<a class="sug-from-url" href="https://www.example.com/blog/how-do-you-get-karma-on-reddit" target="_blank">example.com/blog/how-do-you-get-karma-on-reddit</a>
<div class="sug-divider"></div>
<div class="sug-anchor-label">Anchor Text</div>
<div class="sug-anchor">"karma farming vs building real credibility"</div>
<div class="sug-place-label">Where to Place</div>
<div class="sug-place">After the section on karma-earning tactics, as a cautionary contrast</div>
</div>
</div>
</div>
</div><!-- /.blog-card -->
<!-- C8. ALL CLUSTER TAG VARIANTS
Use .ctag base + one colour modifier.
Map cluster name → class via CC{} in JS. -->
<div style="padding:16px 0 4px;display:flex;flex-wrap:wrap;gap:8px;border-top:1px solid var(--border);margin-top:16px">
<div style="width:100%;font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px">C8 · All cluster tag variants</div>
<span class="ctag c-reddit">Reddit Marketing</span>
<span class="ctag c-devmkt">Developer Marketing</span>
<span class="ctag c-content">Content Marketing</span>
<span class="ctag c-seo">SEO</span>
<span class="ctag c-docs">Documentation</span>
<span class="ctag c-llm">LLM / AI Visibility</span>
<span class="ctag c-gtm">GTM Strategy</span>
<span class="ctag c-devrel">DevRel</span>
<span class="ctag c-techwrite">Technical Writing</span>
<span class="ctag c-product">Product</span>
<span class="ctag c-other">Other</span>
</div>
</div><!-- /.cluster-section -->
</div><!-- /#content -->
</div><!-- /.main -->
<!-- C9. FOOTER -->
<footer>
<span>example.com · Internal Linking Audit · May 27 2026</span>
<span>Source: Ahrefs site-explorer-pages-by-internal-links (site-wide)</span>
</footer>
<!--
══════════════════════════════════════════════════════════════════════
D. JAVASCRIPT REFERENCE
Copy D1–D4 verbatim. Replace CC{} cluster map and D[] data array
with real audit data. Do not modify filterAll() logic.
══════════════════════════════════════════════════════════════════════
-->
<script>
// D1. CLUSTER → CSS CLASS MAP
// Add/remove entries to match actual clusters in the audit.
const CC = {
"Reddit Marketing": "c-reddit",
"Developer Marketing": "c-devmkt",
"Content Marketing": "c-content",
"SEO": "c-seo",
"Documentation": "c-docs",
"LLM / AI Visibility": "c-llm",
"GTM Strategy": "c-gtm",
"DevRel": "c-devrel",
"Technical Writing": "c-techwrite",
"Product": "c-product",
"Other": "c-other"
};
// D2. DATA ARRAY
// Each object = one orphan page.
// url — full URL of orphan
// title — display title
// kw — top keyword string (or "")
// tr — monthly traffic integer, or null
// cluster — must match a key in CC
// s — exactly 3 suggestion objects:
// from — source page title
// fromUrl — source page full URL
// anchor — anchor text (no quotes; JS adds them)
// place — placement guidance
const D = [
{
url: "https://www.example.com/blog/reddit-karma-farming-vs-credibility",
title: "Karma Farming vs Credibility on Reddit",
kw: "reddit karma farming",
tr: null,
cluster: "Reddit Marketing",
s: [
{ from: "Dos and Don'ts of Reddit Marketing", fromUrl: "https://www.example.com/blog/reddit-marketing", anchor: "karma farming on Reddit", place: "In the 'What to Avoid' section when listing bad Reddit practices", copy: "Avoid <a href=\"https://www.example.com/blog/reddit-karma-farming-vs-credibility\">karma farming on Reddit</a>, which signals inauthenticity to both algorithms and community moderators." },
{ from: "Best Subreddits to Join for B2B SaaS Startups", fromUrl: "https://www.example.com/blog/best-subreddits", anchor: "karma vs credibility debate", place: "In the intro when explaining why genuine participation matters", copy: "Before diving into subreddit selection, it helps to understand the <a href=\"https://www.example.com/blog/reddit-karma-farming-vs-credibility\">karma vs credibility debate</a> so your team starts with the right priorities." },
{ from: "How Do You Get Karma on Reddit", fromUrl: "https://www.example.com/blog/how-do-you-get-karma-on-reddit", anchor: "karma farming vs building real credibility", place: "After the section on karma-earning tactics, as a cautionary contrast", copy: "If you want lasting influence rather than just a high score, read our take on <a href=\"https://www.example.com/blog/reddit-karma-farming-vs-credibility\">karma farming vs building real credibility</a> before optimising for points alone." }
]
}
// … all other orphan objects
];
// D3. SIDEBAR + SECTION BUILDER — copy verbatim
const clusters = [...new Set(D.map(b => b.cluster))];
const sidebar = document.getElementById('sidebar');
const content = document.getElementById('content');
clusters.forEach(cl => {
const items = D.filter(b => b.cluster === cl);
const link = document.createElement('div');
link.className = 'sidebar-link';
link.dataset.cluster = cl;
link.innerHTML = `<span>${cl}</span><span class="sc">${items.length}</span>`;
link.onclick = () => {
document.getElementById('clusterFilter').value = cl;
filterAll();
document.querySelectorAll('.sidebar-link').forEach(l => l.classList.remove('active'));
link.classList.add('active');
document.getElementById('sec-' + cl.replace(/\s+\//g,'-').replace(/\s+/g,'-'))?.scrollIntoView({behavior:'smooth',block:'start'});
};
sidebar.appendChild(link);
const sec = document.createElement('div');
sec.className = 'cluster-section';
sec.id = 'sec-' + cl.replace(/\s+\//g,'-').replace(/\s+/g,'-');
sec.innerHTML = `<div class="cluster-header"><div class="cluster-title">${cl}</div><span class="cluster-badge">${items.length} blogs</span></div>`;
items.forEach(b => {
const domain = new URL(b.url).hostname.replace('www.','');
const slug = new URL(b.url).pathname.replace(/^\//, '');
const cc = CC[b.cluster] || 'c-other';
let trHtml;
if (b.tr===null||b.tr===undefined) trHtml='<span class="kw-traffic">—</span>';
else if (b.tr>=10) trHtml=`<span class="kw-traffic hot">▲ ${b.tr} visits/mo</span>`;
else if (b.tr>0) trHtml=`<span class="kw-traffic">▲ ${b.tr} visits/mo</span>`;
else trHtml='<span class="kw-traffic">ranking · 0 traffic</span>';
const sugsHtml = b.s.map((s,i) => {
const sDomain = new URL(s.fromUrl).hostname.replace('www.','');
const sPath = new URL(s.fromUrl).pathname.replace(/^\//, '');
return `<div class="sug-cell">
<div class="sug-num">Suggestion ${i+1}</div>
<div class="sug-from-title">${s.from}</div>
<a class="sug-from-url" href="${s.fromUrl}" target="_blank">${sDomain}/${sPath}</a>
<div class="sug-divider"></div>
<div class="sug-anchor-label">Anchor Text</div>
<div class="sug-anchor">"${s.anchor}"</div>
<div class="sug-place-label">Where to Place</div>
<div class="sug-place">${s.place}</div>
${s.copy ? `<div class="sug-divider"></div><div class="sug-anchor-label">Suggested Context Copy</div><div class="sug-copy">${s.copy}</div>` : ''}
</div>`;
}).join('');
const card = document.createElement('div');
card.className = 'blog-card';
card.dataset.title = b.title.toLowerCase();
card.dataset.url = new URL(b.url).pathname.toLowerCase();
card.dataset.kw = (b.kw||'').toLowerCase();
card.dataset.cluster = b.cluster;
card.innerHTML = `
<div class="blog-header" onclick="this.closest('.blog-card').classList.toggle('open')">
<div class="blog-title-col">
<div class="blog-name">${b.title}</div>
<a class="blog-url" href="${b.url}" target="_blank" onclick="event.stopPropagation()">${domain}/${slug}</a>
</div>
<div class="blog-kw-col">
<span class="kw-pill">${b.kw||'—'}</span>
${trHtml}
</div>
<div class="blog-cluster-col"><span class="ctag ${cc}">${b.cluster}</span></div>
<div class="chevron">▼</div>
</div>
<div class="blog-body"><div class="sug-grid">${sugsHtml}</div></div>`;
sec.appendChild(card);
});
content.appendChild(sec);
});
const allLink = document.createElement('div');
allLink.className = 'sidebar-link active';
allLink.innerHTML = `<span>All Clusters</span><span class="sc">${D.length}</span>`;
allLink.onclick = () => {
document.getElementById('clusterFilter').value = '';
filterAll();
document.querySelectorAll('.sidebar-link').forEach(l => l.classList.remove('active'));
allLink.classList.add('active');
};
sidebar.insertBefore(allLink, sidebar.firstChild);
sidebar.insertBefore(Object.assign(document.createElement('div'),{className:'sidebar-heading',textContent:'Clusters'}), allLink.nextSibling);
// D4. FILTER FUNCTION — copy verbatim, do not modify
function filterAll() {
const q = document.getElementById('searchInput').value.toLowerCase();
const cf = document.getElementById('clusterFilter').value;
let visible = 0;
document.querySelectorAll('.blog-card').forEach(card => {
const mq = !q || card.dataset.title.includes(q) || card.dataset.url.includes(q) || card.dataset.kw.includes(q);
const mc = !cf || card.dataset.cluster === cf;
if (mq && mc) { card.classList.remove('hidden'); visible++; }
else card.classList.add('hidden');
});
document.getElementById('vc').textContent = visible;
document.getElementById('noResults').style.display = visible===0 ? 'block' : 'none';
document.querySelectorAll('.cluster-section').forEach(sec => {
const hasVisible = [...sec.querySelectorAll('.blog-card')].some(c => !c.classList.contains('hidden'));
sec.style.display = hasVisible ? '' : 'none';
});
}
</script>
</body>
</html>Related skills
FAQ
What does orphan-pages-internal-linking-opportunities do?
orphan-pages-internal-linking-opportunities is a workflow skill that audits a site’s content section for orphan pages—URLs no other page links to—and turns each gap into actionable internal links.
When should I use orphan-pages-internal-linking-opportunities?
When you need to find blog and content URLs with zero internal links and get three paste-ready linking suggestions per orphan in an HTML audit report., or when orphan-pages-internal-linking-opportunities is a workflow skill that audits a site’s content section for orphan pages—ur
What are the main capabilities?
Discovers content URLs via sitemap and flags zero incoming internal links (Ahrefs); Clusters orphan pages by topic and derives keywords per URL; Generates 3 linking suggestions per orphan with anchor text, placement, and copy-paste context.