# SEO Auditing

> Audit and improve technical SEO and organic-search performance for small and medium websites, including Search Console, GA4, rendering strategy, raw HTML crawlability, metadata, canonical URLs, redirects, sitemaps, robots directives, JSON-LD, internal links, social previews, accessibility, and Core Web Vitals. Use when the agent builds, reviews, launches, migrates, or diagnoses indexing, traffic, CTR, conversions, or performance for a public website.

- Skill: `dreamers-laboratory/seo-auditing` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add dreamers-laboratory/seo-auditing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dreamers-laboratory/seo-auditing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: dreamers-laboratory (https://skillmd.com/u/dreamers-laboratory)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/dreamers-laboratory/seo-auditing

---


# SEO Auditing

Audit the actual production contract: HTTP responses, serialized HTML, internal links, structured data, and search-engine reports. Do not equate a browser-rendered page with an indexable page.

## Operating Rules

- Prefer static-site generation or prerendered HTML for public content pages.
- Use SSR only when request-time data, personalization, localization, authorization, or freshness genuinely requires it.
- Use client-side JavaScript for enhancement and interaction, not as the only source of indexable content.
- Never serve materially different content to crawlers and users. Hydration may change presentation, but the raw HTML and hydrated page must describe the same page.
- Prefer JSON-LD for structured data. Mark up only visible, accurate content and use the most specific applicable type.
- Treat title and description lengths as display heuristics, not protocol limits. Prioritize unique, accurate, useful text.
- Treat robots.txt as crawl control, not access control or canonicalization.
- Treat Search Console as delayed evidence, not a substitute for live HTTP and HTML checks.
- Verify the active analytics account, property, site, date range, time zone, and filters before interpreting data.
- Corroborate business outcomes across analytics and the authoritative backend when access exists. A click or form attempt is not a lead unless the event definition says so.
- Keep audits read-only unless the user explicitly asks for fixes or deployment.
- Do not enable cloud APIs, alter authentication, redefine analytics events, request indexing, push CMS content, or create hidden persona/state files unless the user explicitly asks.

## Rendering Decision

Choose the least dynamic architecture that satisfies the product:

1. **SSG/prerender**: Default for marketing, documentation, portfolios, services, articles, case studies, rankings, and other public pages that can be built ahead of time.
2. **SSR**: Use for public pages whose HTML must vary per request or whose data cannot tolerate build-time freshness.
3. **CSR**: Reserve for authenticated tools, highly interactive applications, or non-indexable surfaces. If the route should rank, emit meaningful HTML before JavaScript.

For every indexable URL, prove that a plain HTTP client receives:

- `200` without a redirect.
- A unique title, useful description, self-canonical, and correct robots policy.
- The page's primary heading and substantive body content.
- Crawlable links to related canonical URLs.
- Valid JSON-LD appropriate to the visible page when a useful schema type exists.

## Workflow

### 1. Establish Scope

Read the repository's project context, route registry, build configuration, hosting rules, and deploy documentation. Record:

- Production origin and canonical host/scheme.
- URL style, including trailing-slash policy.
- Intended indexable and intentionally excluded routes.
- Rendering mode per route family.
- Sitemap, robots, redirect, and error-response ownership.

Preserve dirty worktrees. Do not rebuild or edit generated output until ownership is clear.

### 2. Reconcile Route Sets

For a small site, audit every sitemap URL. Compare these sets:

1. Intended canonical indexable routes.
2. Generated or server-rendered HTML routes.
3. Sitemap URLs.
4. Internally linked canonical URLs.

Investigate every difference. A route should not be indexable merely because React can navigate to it.

### 3. Run The Raw-HTML Audit

Use the bundled audit first:

```bash
node scripts/audit-static-site.mjs \
  --origin https://example.com
```

The script is read-only and prints JSON to stdout. It checks sitemap URLs without executing JavaScript. Treat missing substantive raw HTML, invalid JSON-LD, redirecting sitemap URLs, canonical mismatches, duplicate titles, and broken internal links as failures.

Use `--sample N` only for large sites. For small sites, do not sample.

### 4. Inspect Architecture And Source

Confirm that:

- The route registry drives prerender output, canonical URLs, sitemap membership, and metadata from one source of truth where practical.
- Canonical pages return `200`; noncanonical host/scheme/path variants use one-hop permanent redirects (`301` or `308`).
- Temporary redirects (`302` or `307`) are used only for genuinely temporary routing.
- Missing pages return a real `404` or `410`, not a branded `200` soft-404.
- Canonical, sitemap, internal links, `og:url`, and hreflang all use the same final URL.
- Indexable HTML does not depend on cookies, browser storage, a service worker, or JavaScript execution.

### 5. Validate Structured Data

Prefer JSON-LD. Use stable `@id` values and connect entities when useful:

- Site/home: `Organization` or the applicable subtype plus `WebSite`.
- General page: `WebPage` and, where useful, `BreadcrumbList`.
- Editorial content: `Article`, `BlogPosting`, or a more specific subtype.
- Product, service, local business, job, event, software, profile, and other pages: use the documented type only when the visible page satisfies its requirements.

Do not add FAQ, review, rating, author, date, price, availability, or organization claims that are absent or misleading on the visible page. Validation eligibility does not guarantee a rich result.

### 6. Validate Discovery And Control Files

- Sitemap contains only canonical, indexable `200` URLs.
- `lastmod` is present only when it can reflect meaningful page changes accurately.
- Robots.txt does not block render-critical assets or pages whose `noindex` must be read.
- Robots.txt references the canonical sitemap.
- Noindex pages are excluded from the sitemap but may use `follow` when link discovery is useful.
- Use `X-Robots-Tag` for non-HTML resources when needed.
- `llms.txt` may aid machine discovery but is optional and never replaces HTML, links, robots, canonicals, or sitemaps.

### 7. Validate User-Facing Signals

Check representative pages with a browser and mobile viewport:

- Heading structure, language, landmarks, link text, image alt text, and keyboard access.
- Open Graph and Twitter metadata with an absolute, fetchable image.
- Image dimensions/aspect ratios to prevent layout shift.
- Core Web Vitals using field data when available; use Lighthouse as laboratory evidence only.
- Hydration parity: the rendered page must retain the same canonical, metadata, main content, and structured data as the raw response.

Read [references/audit-checklist.md](references/audit-checklist.md) when performing a full launch, migration, or indexing diagnosis.

### 8. Inspect Search And Analytics

Use the authenticated source already available to the user. Prefer direct product reports or an existing read-only API; do not introduce a new cloud project or authentication flow merely to run an audit.

For portfolio analytics, use the user's authenticated browser as the primary GA4 and Search Console surface. Check that browser before concluding that authentication is unavailable. Keep the work read-only and do not change users, roles, properties, streams, events, key events, links, filters, or indexing state unless the user separately requests the change.

When the user asks for analytics across all managed sites, inventory the portfolio before analyzing it. Reconcile the GA4 account/property/stream picker, the Search Console property picker, and the known production-host inventory. Include every managed production hostname, including sites with no GA4 property, no Search Console property, or no recent data; report those as measurement gaps rather than silently dropping them. Do not treat subpages as separate sites, but retain hostname-level separation for subdomains and independent products.

Default the portfolio report to a high-level scorecard with one row per site or hostname:

- GA4 sessions, users, organic sessions, engagement rate, and confirmed-submission key events for the latest complete 28 days versus the prior 28 days.
- Search Console clicks, impressions, CTR, and average position for the same comparison, plus a compact 90-day context signal.
- Primary acquisition change, strongest organic page or query, material tracking caveat, and a plain-language status such as growing, flat, declining, too little data, or unmeasured.

Keep the first pass comparable and concise. Drill into pages, queries, devices, sources, or event definitions only for material movers, business-priority sites, suspected tracking defects, or sites the user specifically names. Separate portfolio totals from site-level metrics; do not combine unrelated domains into a synthetic average that hides weak or unmeasured properties.

When an existing Search Console API credential is already authorized, use the bundled collector:

```bash
node scripts/gsc-performance.mjs \
  --site sc-domain:example.com \
  --brand-term example \
  --output /tmp/example-gsc-audit.json
```

It pages through query, page, and query/page reports; keeps property totals separate from visible-query totals; compares the latest complete period with the prior period; segments devices, countries, search appearances, search types, and URL families; and decomposes declining pages into their losing visible queries. Treat its cannibalization output as a review queue, never as an automatic redirect or canonical recommendation.

Inspect representative URLs in a read-only batch when the same credential permits it:

```bash
node scripts/gsc-url-inspection.mjs \
  --site sc-domain:example.com \
  --url https://example.com/ \
  --url https://example.com/important-page/
```

The API reports Google's indexed version, not a live URL test. If existing credentials lack the required scope, use authenticated Search Console in Chrome. Do not reauthenticate, enable an API, or change a Google Cloud project just to make the scripts run.

For a current performance review, collect:

- Search Console's latest complete 28 days versus the previous 28 days, plus a 90-day context window.
- Clicks, impressions, CTR, and average position, with absolute and percentage changes where the denominator is meaningful.
- Branded versus non-branded demand, device, country, search appearance, page family, and query-to-page mappings.
- Exact query/page filters for suspected cannibalization; do not infer cannibalization from similar titles alone.
- URL Inspection for representative winners, declining pages, new pages, and reported indexing examples.
- GA4 acquisition, landing pages, engagement, and configured key events for the same period where practical.

State that Search Console query rows can omit anonymized low-volume queries. Do not treat the sum of visible query rows as the property total or silently mix differently filtered reports.

Before calling a GA4 event a conversion or lead, inspect its definition and key-event status. Distinguish CTA clicks, form starts, validation failures, submission attempts, confirmed submissions, and downstream qualified leads. When a contact database, mail service, or CRM is the authoritative record, reconcile analytics successes to it read-only and identify tests, spam, duplicates, and source/origin fields.

Treat source attribution as evidence, not proof of causation. Explain the report's attribution model and distinguish first-user acquisition, session acquisition, and event attribution. A paid-source session does not by itself prove an ad generated a lead or incremental value.

### 9. Measure Performance Correctly

Use Core Web Vitals field data at the 75th percentile when available. Report its population and window. If field data is unavailable, say so; do not generalize a synthetic run to typical visitors.

Use PageSpeed Insights or Lighthouse as laboratory diagnostics:

- Record mobile or desktop, emulated device, network and CPU throttling, run time, tested URL, and whether the result is lab or field data.
- Inspect the actual LCP element and its request/render breakdown, not just the score.
- Cross-reference payload size, image delivery, render-blocking work, main-thread work, third parties, cache policy, and representative route templates.
- Fall back from a quota-limited PageSpeed API to the PageSpeed UI or local Lighthouse without changing cloud configuration.
- Describe lab LCP as when the largest above-the-fold element rendered under the test conditions, not as every user's full page-load time.

For repeatable PageSpeed collection across representative templates, run:

```bash
node scripts/pagespeed-batch.mjs \
  --url https://example.com/ \
  --url https://example.com/important-page/ \
  --strategy both \
  --output /tmp/example-pagespeed.json
```

The script uses `PAGESPEED_API_KEY` only if it is already present in the environment. It records field and lab evidence separately, the Lighthouse environment, the detected LCP element when the response exposes it, opportunities, resource totals, and the largest transferred resources. An API failure is a documented fallback condition, not permission to create credentials or enable services.

## Reporting

Lead with findings, ordered by severity:

- **Critical**: deindexing, robots block, invalid status behavior, canonical to the wrong page, missing raw content, broken production route.
- **High**: sitemap/canonical conflict, widespread duplicate metadata, orphan canonical pages, invalid or misleading structured data, redirect chains.
- **Medium**: weak internal linking, incomplete schema, social-preview defects, accessibility or performance regressions.
- **Low**: length heuristics, optional metadata, minor cleanup.

For each finding provide the affected URL or file, observed evidence, impact, and exact fix. Separate:

1. Live defects.
2. Intentional exclusions and expected aliases.
3. Search-engine lag or discretionary indexing.
4. Unverified risks and test gaps.

Do not promise indexing. A technically correct page can still remain unindexed.

For a performance or growth review, finish with three to five evidence-backed priorities. Tie each priority to the affected page/query/event, observed evidence, expected mechanism, and a verification metric. Show before/after title or description copy when recommending metadata changes. Do not use generic position-to-CTR curves as forecasts without accounting for query intent, SERP features, zero-click behavior, and AI-generated summaries.

Add a short **What To Ignore For Now** section. Include only low-impact findings, intentional exclusions, platform lag, weak-sample observations, or changes whose expected value does not justify current effort. Give the reason so deferred work is not mistaken for forgotten work.

Create an audit-history artifact only when the user requests one or the project already has an established location and format. Keep provenance, date ranges, and unresolved gaps with the result.

## Related Skills

- Use `content-generator` for substantial page-copy and keyword-map work.
- Use `gsc-indexing` for authenticated Search Console inspection and indexing requests.
- Use `git-deploy-release` for commits, releases, and deployment.

