Optimizing On-Page
Overview
The per-page workhorse. While auditing-technical-seo works at the site level and finding-underserved-keywords decides what to target, this skill executes the per-URL surgery: rewrite the title, tighten the meta, fix the H1/H2 spine, weave in internal links with descriptive anchor text, sweep alt text, and front-load a featured-snippet-capable answer. One URL in, one focused PR out. No site-wide refactors, no Notion docs.
When to use
- "Optimize this page" / "fix the SEO on
/blog/foo" - A single blog post, landing page, or doc page needs polish
finding-underserved-keywordsproduced a keyword cluster to integrate into one page- A page ranks position 5–15 but the title/snippet is the bottleneck
- An internal-linking or alt-text sweep was requested for one URL
- You inherited a markdown/MDX file and need to ship it SEO-tight
Don't use for: site-wide audits (auditing-technical-seo), pre-launch setup (seo-bootstrap), JSON-LD work (adding-schema-markup), or keyword discovery (finding-underserved-keywords).
What this skill checks
- Title tag — under
600px (50–60 chars), primary keyword in first 30–35 chars, no brand-doubling [1]. - Meta description — 140–155 chars (mobile truncates ~120) [2]; intent-aligned, value prop early.
- H1 — exactly one per page, ≤60 chars, distinct from
<title>(no H1=title duplication), reads like a headline not a keyword string [3]. - H2/H3 nesting — logical hierarchy, no level skipping (H1→H3), H2s mirror search-intent sub-questions [3].
- Featured-snippet readiness — direct ~40–50 word answer in the first paragraph of the relevant section, ideally under an H2 phrased as the question [6].
- Internal links — 2–5 contextual links per 1,000 words, descriptive anchor text (not "click here"), majority in body (top 30%), under 150 total page links [4].
- Anchor-text variety — ~15–25% exact match, ~30–40% partial, ~25–35% semantic [4]. No single anchor repeated to the same destination.
- Alt text — descriptive, 50–125 chars, no "image of",
alt=""for decorative; no keyword stuffing [5]. - Intent match — page type (informational / commercial / transactional) matches what live SERP shows for the primary query.
The optimization flow
- Read the page. If a file path: open the markdown/MDX (or
.tsx/.astro/.svelteroute). If a URL: fetch the live HTML. Extract current<title>, meta description, headings tree, link graph, image alts. - Pull keyword context. If
finding-underserved-keywordsran recently and produced a striking-distance cluster for this URL, load it. If not, ask the user for the primary query (one question, then move). - Lighthouse SEO baseline. Call
lighthouse-mcpand capture pass/fail on the 8 SEO audits (title, meta, alt, link text, indexability, robots, canonical, hreflang) [7]. Lighthouse pass is the floor, not the ceiling. - Rank gaps by impact. Order: title > meta > H1 > featured-snippet paragraph > H2/H3 spine > internal links > alt text. Title/meta drive CTR on impressions you already earn — biggest dollar-per-edit.
- Propose edits as diffs. For each gap, show before/after side-by-side with the rule it satisfies. No prose explanations longer than the edit itself.
- Open ONE PR for this URL. Title:
seo: optimize on-page for /<slug>. Body lists each change + the rule. No drive-by site-wide changes.
Anti-patterns / common mistakes
- Brand-doubling in title —
Make a Capsule Wardrobe | Vibecrafting | Vibecrafting(a real bug we hit in the wild). Brand goes once, at the end, separated by|or—. - Clickbait titles — Google rewrites them, killing your CTR control.
- H1 = page title — verbatim duplication wastes a heading slot; H1 should expand or rephrase.
- Keyword stuffing alt text or H2s — alt becomes spam signal; H2s lose snippet eligibility.
- Generic alt text ("image", "photo", "logo") — fails accessibility AND AI-citation crawlers [5].
- "Click here" / "learn more" anchors — kills accessibility, gives Google nothing [4].
- Too many internal links (>150 page total or >10 to same destination) — dilutes equity.
- Intent mismatch — adding transactional CTAs to an informational page Google ranks for "how does X work".
- Editing without checking the live SERP — what currently ranks tells you the intent contract.
Quick reference — if I want X, change Y
| Goal | Edit | Rule |
|---|---|---|
| More clicks on existing impressions | Title + meta description | <600px / 140–155 chars [1][2] |
| Featured snippet capture | Add 40–50 word answer under question-phrased H2 | First paragraph, definition format [6] |
| Higher topical authority | H2/H3 spine + internal links | Logical nesting, descriptive anchors [3][4] |
| AI-search citations (ChatGPT/Claude/Perplexity) | Alt text + FAQ block + clear H-spine | Crawlable text, no JS-only content [5] |
| Fix a CTR-dead page (pos 1–10, no clicks) | Rewrite title + meta only | Don't touch body |
| Fix a content-gap page (pos 5–15, low clicks) | Weave keywords into H2/H3/body | Hand off from finding-underserved-keywords |
Lifecycle awareness
- New page (0–3 mo): Get the title, meta, H1, and one featured-snippet paragraph right at publish. Add 3–5 internal links from authority pages. Don't optimize for queries yet — there's no GSC data to listen to.
- Growth page (3–12 mo): This is the sweet spot. Pair with
finding-underserved-keywordsoutput. Weave striking-distance terms into H2/H3, body, alt, anchor text. Rewrite meta if CTR is below the position-expected baseline. - Mature page (12+ mo): Decay defense. Refresh title/meta if SERP intent has shifted. Re-check featured-snippet paragraph against the current top result. Audit internal links — broken or stale destinations leak equity. Update
<lastmod>-relevant content for AI-citation freshness.
What next
- JSON-LD missing or stale? Hand off to
adding-schema-markup(Article/BlogPosting/FAQPage as appropriate). - No keyword data driving the edit? Run
finding-underserved-keywordsfirst, then come back here. - Other pages need the same treatment? Loop this skill per URL — one PR per page keeps reviews tight.
Citations and verification tags in SOURCES.md.