SKILL.md
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
- Normalize the input domain:
- Strip leading/trailing whitespace - If it doesn't start with http, prepend https:// - If it doesn't have www. and the base domain resolves with it, use www. - Remove any trailing slash - Store as BASE_URL (e.g., https://www.example.com)
- Fetch
BASEURL/robots.txtusing WebFetch. Look for anySitemap:directive — if found, use that URL as the sitemap location. If not found, default toBASEURL/sitemap.xml.
- 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
- Store the full master URL list.
PHASE 2 — Blog URL Identification
From the master URL list:
- 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/
- Select the prefix that best represents the blog content (most URLs, most uniform structure). If multiple prefixes qualify, include all of them.
- Filter the master URL list to only include URLs matching the identified blog prefix(es). Exclude index/listing pages (e.g.,
BASEURL/blogwith no further slug). Store asBLOGURLS.
- If no blog prefix is identifiable from the sitemap, fetch
BASE_URLhomepage and look for a blog/articles navigation link, then fetch that page and extract all post URLs from it.
- 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 { sourceurl, outboundblog_links: [...] }
- Use schema:
{ type: 'object', properties: { sourceurl: { type: 'string' }, outboundbloglinks: { type: 'array', items: { type: 'string' } } }, required: ['sourceurl', 'outboundbloglinks'] }
After the workflow completes, aggregate results:
- Build
inboundcountmap:{ url -> number }initialized to 0 for allBLOGURLS - Build
inboundsourcesmap:{ url -> [sourceurl, ...] }initialized to[]for allBLOG_URLS - For each crawl result, iterate
outboundbloglinksand 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
LOWLINKEDURLS - Healthy = 3+ inbound links → store as
HEALTHY_URLS
Build FULLINBOUNDMAP: 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__claudeaiDataForSEO__kwdatagoogleadssearchvolume, then calls it with the keyword variants, locationcode: 2840 (United States), languagecode: "en" 4. Picks the keyword with the highest US monthly search volume as anchortext 5. Fallback: if DataForSEO returns no data or errors, convert the slug to a phrase (hyphens → spaces) as the anchortext 6. Fetches the page and writes a 2–3 sentence pagesummary of what the page covers 7. Returns { orphanurl, anchortext, usmonthlyvolume, page_summary }
- Use schema:
{ type: 'object', properties: { orphanurl: { type: 'string' }, anchortext: { type: 'string' }, usmonthlyvolume: { type: 'number' }, pagesummary: { type: 'string' } }, required: ['orphanurl', 'anchortext', 'usmonthlyvolume', 'pagesummary'] }
Store results as KEYWORDDATA: map of { orphanurl -> { anchortext, usmonthlyvolume, pagesummary } }
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:
- Receives
orphanurl,anchortext,pagesummary, and the fullBLOGURLSlist - Selects exactly 3 topically relevant source pages from
BLOG_URLS(exclude the orphan itself; prefer well-linked, non-orphan pages) - Fetches each of the 3 source pages using WebFetch
- For each source page produces:
- sourceurl: the full URL of the source page - wheretoplace: 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 guessing - contextcopy: minimum 300 characters of naturally flowing copy to be inserted at that location. The anchortext MUST appear exactly once within it as <a href="ORPHANURL">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.
- Returns
{ orphanurl, anchortext, placements: [{ sourceurl, wheretoplace, contextcopy }, ...] }
- Use schema with
placementsas array of 3 objects each requiringsourceurl,wheretoplace,contextcopy
After the workflow completes, post-process every context_copy:
- Check if
anchortextappears as a hyperlink (href="orphanurl"present) - If not, find the first occurrence of
anchortext(case-insensitive) and replace with<a href="orphanurl">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:
{LOWLINKEDURLS.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 uses navigator.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:
- Report the file path to the user
- Give a brief summary:
- Total blog posts found - Number of orphan pages - Number of interlinking briefs generated - File name and location
- 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
anchortextstring appears in all 3contextcopyblocks 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