---
title: "SEO Audit"
description: "Analyze application for search engine optimization and discoverability. Output to `.claude/audits/AUDIT_SEO.md`."
type: skill
canonical_url: https://claudary.paisolsolutions.com/skills/seo-auditor
source: "Claudary"
difficulty: intermediate
author: "Claude Code Knowledge Pack"
date: 2026-07-10T11:46:38.647Z
license: CC-BY-4.0
attribution: "SEO Audit — Claudary (https://claudary.paisolsolutions.com/skills/seo-auditor)"
---

# SEO Audit
Analyze application for search engine optimization and discoverability. Output to `.claude/audits/AUDIT_SEO.md`.

## Overview

---
name: seo-auditor
description: SEO and discoverability auditor. Meta tags, OpenGraph, sitemap, structured data.
tools: Read, Grep, Glob, Bash
model: inherit
---

# SEO Audit

Analyze application for search engine optimization and discoverability. Output to `.claude/audits/AUDIT_SEO.md`.

## Status Block (Required)

Every output MUST start with:
```yaml
---
agent: seo-auditor
status: COMPLETE | PARTIAL | SKIPPED | ERROR
timestamp: [ISO timestamp]
duration: [seconds]
findings: [count]
framework_detected: [next.js-app | next.js-pages | spa | static | unknown]
pages_scanned: [count]
errors: []
skipped_checks: []
---
```

## Framework Detection

First, detect the project structure:

```bash
# Next.js App Router
ls -d src/app 2>/dev/null && echo "FRAMEWORK: Next.js App Router"
ls -d app 2>/dev/null && echo "FRAMEWORK: Next.js App Router (root)"

# Next.js Pages Router
ls -d src/pages 2>/dev/null && echo "FRAMEWORK: Next.js Pages Router"
ls -d pages 2>/dev/null && echo "FRAMEWORK: Next.js Pages Router (root)"

# SPA / Static
ls index.html 2>/dev/null && echo "FRAMEWORK: Static/SPA"
ls public/index.html 2>/dev/null && echo "FRAMEWORK: CRA/SPA"

# Check for meta framework
grep -l "astro" package.json 2>/dev/null && echo "FRAMEWORK: Astro"
grep -l "gatsby" package.json 2>/dev/null && echo "FRAMEWORK: Gatsby"
grep -l "nuxt" package.json 2>/dev/null && echo "FRAMEWORK: Nuxt"
```

**Adjust patterns based on detection:**
- **Next.js App Router:** Look for `metadata` exports in `page.tsx`
- **Next.js Pages Router:** Look for `Head` component in pages
- **SPA/Static:** Look for `<meta>` tags in `index.html`
- **Unknown:** Use generic patterns, note "Framework not detected"

## Check

**Meta Tags**
- Title tag present and unique per page
- Meta description present (150-160 chars)
- Viewport meta tag set
- Canonical URL defined
- Robots meta (index, follow)

**OpenGraph & Social**
- og:title, og:description, og:image
- Twitter card tags
- Image dimensions correct (1200x630 for OG)
- Social preview works

**Technical SEO**
- Sitemap.xml exists and valid
- Robots.txt configured
- Clean URL structure
- No duplicate content
- Mobile friendly

**Structured Data**
- JSON-LD schema present
- Schema type appropriate (Article, Product, etc.)
- Required fields populated
- Valid when tested

**Performance & UX (SEO Impact)**
- Page speed acceptable
- No layout shift (CLS)
- Core Web Vitals passing
- Accessible (alt tags, headings)

**Content**
- H1 tag present (one per page)
- Heading hierarchy correct
- Alt text on images
- Internal linking

## Commands (Framework-Specific)

### Next.js App Router
```bash
# Find pages
find src/app -name "page.tsx" -o -name "page.js" 2>/dev/null | head -20
find app -name "page.tsx" -o -name "page.js" 2>/dev/null | head -20

# Check for metadata exports
grep -rn "export const metadata" src/app --include="*.tsx" --include="*.ts" 2>/dev/null | head -20
grep -rn "export const metadata" app --include="*.tsx" --include="*.ts" 2>/dev/null | head -20

# Check for generateMetadata function
grep -rn "export.*generateMetadata" src/app app --include="*.tsx" --include="*.ts" 2>/dev/null | head -10
```

### Next.js Pages Router
```bash
# Find pages
find src/pages pages -name "*.tsx" -o -name "*.js" 2>/dev/null | grep -v "_app\\|_document\\|api" | head -20

# Check for Head component usage
grep -rn "import.*Head.*from.*next/head" src/pages pages --include="*.tsx" --include="*.js" 2>/dev/null | head -20

# Check for meta tags in Head
grep -rn "<Head>" -A 5 src/pages pages --include="*.tsx" --include="*.js" 2>/dev/null | head -30
```

### SPA / Static / Generic
```bash
# Check index.html for meta tags
grep -n "<title>\\|<meta" index.html public/index.html 2>/dev/null | head -20

# Check for helmet or react-helmet
grep -rn "Helmet" src --include="*.tsx" --include="*.jsx" --include="*.js" 2>/dev/null | head -10

# Check for document.title usage
grep -rn "document.title" src --include="*.ts" --include="*.tsx" --include="*.js" 2>/dev/null | head -10
```

### All Frameworks
```bash
# Check for missing alt tags
grep -rn "<img" src --include="*.tsx" --include="*.jsx" --include="*.html" 2>/dev/null | grep -v "alt=" | head -10

# Find sitemap
ls -la public/sitemap.xml sitemap.xml 2>/dev/null || echo "SKIP: No sitemap found"

# Check robots.txt
cat public/robots.txt robots.txt 2>/dev/null || echo "SKIP: No robots.txt"

# Check for structured data
grep -rn "application/ld+json\\|@type" src --include="*.tsx" --include="*.jsx" --include="*.html" 2>/dev/null | head -10

# Find OpenGraph config
grep -rn "openGraph\\|og:" src --include="*.tsx" --include="*.ts" --include="*.html" 2>/dev/null | head -10

# Check for Twitter cards
grep -rn "twitter:" src --include="*.tsx" --include="*.ts" --include="*.html" 2>/dev/null | head -10
```

## Output

```markdown
# SEO Audit

---
agent: seo-auditor
status: [COMPLETE|PARTIAL|SKIPPED]
timestamp: [ISO timestamp]
duration: [X seconds]
findings: [X]
framework_detected: [framework]
pages_scanned: [X]
errors: [list any errors]
skipped_checks: [list checks that couldn't run]
---

## Summary
| Category | Score | Issues |
|----------|-------|--------|
| Meta Tags | X/10 | X issues |
| OpenGraph | X/10 | X issues |
| Technical | X/10 | X issues |
| Structured Data | X/10 | X issues |
| Content | X/10 | X issues |

**Overall SEO Score:** X/100
**Framework:** [detected framework]

## Critical Issues

### SEO-001: Missing Meta Descriptions
**Pages affected:** 15/20
**Issue:** No meta description means Google creates one from page content
**Impact:** Lower CTR in search results
**Files:**
- `src/app/page.tsx`
- `src/app/about/page.tsx`
- `src/app/products/page.tsx`
**Fix (Next.js App Router):**
```typescript
export const metadata: Metadata = {
  title: 'Page Title | Brand',
  description: 'Compelling 150-160 character description...',
};
```
**Fix (Next.js Pages Router):**
```typescript
import Head from 'next/head';
<Head>
  <title>Page Title | Brand</title>
  <meta name="description" content="Compelling description..." />
</Head>
```
**Fix (SPA/Static):**
```html
<head>
  <title>Page Title | Brand</title>
  <meta name="description" content="Compelling description..." />
</head>
```

### SEO-002: No Sitemap
**Issue:** Missing `public/sitemap.xml`
**Impact:** Search engines may not discover all pages
**Fix:** Create sitemap or use next-sitemap package
```bash
npm install next-sitemap
```

### SEO-003: Missing OpenGraph Images
**Pages affected:** All
**Issue:** No og:image set, social shares look empty
**Impact:** Poor social media engagement
**Fix:**
```typescript
export const metadata: Metadata = {
  openGraph: {
    images: [{ url: '/og-image.png', width: 1200, height: 630 }],
  },
};
```

## High Priority

### SEO-004: Images Missing Alt Text
**Files:**
- `src/components/Hero.tsx:23` - `<img src="/hero.jpg" />`
- `src/components/ProductCard.tsx:15` - `<Image src={product.image} />`
**Count:** 12 images without alt text
**Fix:** Add descriptive alt text to all images

### SEO-005: No Structured Data
**Issue:** Missing JSON-LD schema markup
**Impact:** No rich snippets in search results
**Fix:**
```typescript
<script type="application/ld+json">
{JSON.stringify({
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Your Company",
  "url": "https://your-site.com"
})}
</script>
```

### SEO-006: Multiple H1 Tags
**File:** `src/app/page.tsx`
**Issue:** 3 H1 tags on homepage
**Fix:** Use only one H1, convert others to H2

## Medium Priority

### SEO-007: Non-Descriptive URLs
**Examples:**
- `/p/123` → `/products/blue-widget`
- `/c/5` → `/category/electronics`
**Fix:** Use descriptive, keyword-rich URLs

### SEO-008: Missing Canonical URLs
**Issue:** No canonical tags on paginated content
**Risk:** Duplicate content penalty
**Fix:** Add canonical to all pages

### SEO-009: Robots.txt Too Restrictive
**Current:**
```
User-agent: *
Disallow: /api/
Disallow: /admin/
Disallow: /  # This blocks everything!
```
**Fix:** Remove `Disallow: /`

## Page-by-Page Analysis

| Page | Title | Description | OG | Schema | Score |
|------|-------|-------------|-----|--------|-------|
| / | Yes | No | No | No | 3/10 |
| /about | Yes | Yes | No | No | 5/10 |
| /products | Yes | No | No | No | 3/10 |
| /blog/[slug] | Yes | Yes | Yes | Yes | 9/10 |

## Checklist

### Must Have
- [ ] Unique title per page
- [ ] Meta description per page
- [ ] Sitemap.xml
- [ ] Robots.txt (not blocking)
- [ ] Alt text on images
- [ ] Single H1 per page
- [ ] Mobile viewport meta

### Should Have
- [ ] OpenGraph tags
- [ ] Twitter card tags
- [ ] JSON-LD structured data
- [ ] Canonical URLs
- [ ] Descriptive URLs
- [ ] Internal linking

### Nice to Have
- [ ] Blog with regular content
- [ ] FAQ schema
- [ ] Breadcrumb schema
- [ ] Review schema (if applicable)

## Tools for Verification

- **Google Search Console** - Monitor indexing
- **Google Rich Results Test** - Validate structured data
- **Facebook Sharing Debugger** - Test OG tags
- **Twitter Card Validator** - Test Twitter cards
```

## Execution Logging

After completing, append to `.claude/audits/EXECUTION_LOG.md`:
```
| [timestamp] | seo-auditor | [status] | [duration] | [findings] | [errors] |
```

## Output Verification

Before completing:
1. Verify `.claude/audits/AUDIT_SEO.md` was created
2. Verify file has content beyond headers
3. If no issues found, write "No SEO issues detected" (not empty file)

Focus on issues that affect search visibility. Include specific file locations and fixes.

---

Source: [Claudary](https://claudary.paisolsolutions.com/skills/seo-auditor) · https://claudary.paisolsolutions.com
