seo
SEO for web apps — metadata, structured data, sitemaps, robots.txt, Core Web Vitals, E-E-A-T. Auto-loads framework-specific references.
SKILL.md.claude/skills/seo/SKILL.md
GitHubSEO
Comprehensive SEO for web apps. The bulk of the implementation lives in references/ — load the one(s) relevant to the user's task. Templates in assets/templates/ are ready-to-paste JSON-LD blocks parameterised on common fields.
When to load each reference
| Task | Reference |
|---|---|
| Per-page metadata, OG tags, Twitter cards in Next.js | references/nextjs-metadata.md |
| Pick the right schema.org type + paste JSON-LD | references/jsonld.md (+ a template from assets/templates/) |
| Generate sitemap.xml or robots.txt | references/sitemap-robots.md |
| Fix LCP/INP/CLS regressions | references/core-web-vitals.md |
| Audit content quality (Experience/Expertise/Authoritativeness/Trust) | references/eeat.md |
Decision tree
Is the page user-facing?
├── No → robots noindex; skip the rest
└── Yes → Continue
│
├── What schema.org type fits?
│ blog post → Article → article-jsonld.json
│ product → Product (+ Offer) → product-jsonld.json
│ service → Service / LocalBusiness
│ org/about → Organization → organization-jsonld.json
│ local biz → LocalBusiness → local-business-jsonld.json
│ event → Event
│ person → Person
│
├── Framework?
│ Next.js App Router → nextjs-metadata.md (Metadata API)
│ Remix → meta() functions
│ Astro → <head> with `Astro.url`
│ Plain HTML → static `<meta>` + `<script type="application/ld+json">`
│
└── Performance?
→ core-web-vitals.md (LCP/INP/CLS playbook)
Run an audit
.claude/skills/seo/scripts/audit.sh https://example.com
The script:
- Runs PageSpeed Insights (mobile + desktop) and prints the LCP/INP/CLS verdicts
- Validates structured data via Google's testing endpoint
- Greps the rendered HTML for missing
<title>,<meta description>, OG tags, canonical - Outputs a checklist of fixes ordered by impact
Quality gates (refuse to ship without these)
| Gate | Why |
|---|---|
metadataBase set on root layout |
Without it, OG image URLs resolve relative — broken on social shares |
| Canonical URL on every page | Prevents duplicate-content penalties |
description 50–160 chars |
Outside this range Google often rewrites your snippet |
og:image 1200×630 + ≤300KB |
Large/wrong-aspect images don't render in feeds |
alt on every content image |
a11y + image search ranking |
| LCP < 2.5s on mobile 4G | Below this is a Web Vitals fail and a CrUX field-data drag |
| Unique title per page | Duplicate titles get clustered in SERPs |
Common pitfalls
- Mixing Next.js Metadata API with
<Head>. Pick one; Metadata API wins for App Router. - Forgetting to escape
</script>inside JSON-LD strings. UsedangerouslySetInnerHTMLwith sanitised input. robots.txtblocking/_next/static/. Don't — Google needs your CSS/JS to render correctly.- Setting
noindexand then linking to the page from elsewhere. Either commit to noindex or remove the inbound links; mixed signals hurt. - Tracking pixels firing during render. Use
next/scriptwithstrategy="lazyOnload"for analytics.