npx skills add ...
npx skills add seo-skills/seo-audit-skill --skill seo-audit
Audit websites for SEO, technical, content, security, JS rendering, and AI readiness using SEOmator CLI. Returns LLM-optimized reports with health scores across 332 rules and 20 categories, and can diff two audits to show what a deploy changed. Use when analyzing websites, debugging SEO issues, checking site health, or comparing a site before and after a change.
npx skills add seo-skills/seo-audit-skill --skill seo-audit
Audit websites for SEO, technical, content, performance, security, JavaScript rendering, and AI readiness using the SEOmator CLI.
SEOmator provides comprehensive website auditing by analyzing website structure and content against 332 rules across 20 categories.
It provides a list of issues with severity levels, affected URLs, and actionable fix suggestions.
This skill enables AI agents to audit websites for 332 rules in 20 categories, including:
--crawl)--mobileThe audit crawls the website, analyzes each page against audit rules, and returns a comprehensive report with:
Use this skill when you need to:
This skill requires the SEOmator CLI to be installed.
Check that seomator is installed and the system is ready:
This checks:
Running seomator init creates a seomator.toml config file in the current directory.
If there is no seomator.toml in the directory, CREATE ONE with seomator init before running audits.
YOU SHOULD always prefer --format llm - it provides token-optimized XML output specifically designed for AI agents (50-70% smaller than JSON).
When auditing:
Prefer live websites over local dev servers for accurate performance and rendering data
Use --no-cwv for faster audits, but know what it costs: it skips the
browser render, so Core Web Vitals, the JavaScript rendering rules,
js-console-errors, js-failed-requests and all mobile-parity-* rules
report unmeasured rather than passing or failing
Match the flags to the question. Rules that need more than one page or more than one render are unmeasured without the right flag:
| To check | Run with |
|---|---|
| Click depth, inbound internal links | --crawl (builds the site graph) |
| Mobile-first indexing parity | --mobile (second render at a phone viewport) |
| JS errors, failed subresources, Core Web Vitals | default (omit --no-cwv) |
| What a deploy changed | run before and after, then seomator compare <domain> |
Scope fixes as concurrent tasks when implementing multiple fixes
Run typechecking/formatting after implementing fixes (tsc, eslint, prettier, etc.)
If the user doesn't provide a website to audit:
If you have both local and live websites available, suggest auditing the live site for accurate results.
Audit specific categories only:
Save HTML report for sharing:
Verbose output for debugging:
An agent must be able to tell "the audit failed" from "the site scored badly". Every command uses the same three:
| Code | Meaning |
|---|---|
0 | Success |
1 | The run worked, and the result is below a threshold — audit/analyze scored under 70, or compare --fail-on-regression found a regression |
2 | The command failed: unreachable URL, HTTP error, missing crawl, bad --config path |
130 | Cancelled with Ctrl-C |
A non-zero exit is not automatically a failure. 1 means the tool worked
and is telling you something about the site. Only 2 means it could not do the
job. Under --format json or --format llm, a 2 also puts a structured
error on stdout with a stable code field:
| Option | Alias | Description | Default |
|---|---|---|---|
--format <fmt> | -f | Output format: console, json, html, markdown, llm | console |
--max-pages <n> | -m | Maximum pages to crawl | 10 |
--crawl | Enable multi-page crawl | false | |
--categories <list> | -c | Comma-separated categories to audit | All |
--no-cwv | Skip Core Web Vitals + JS rendering | false | |
--mobile | Render mobile viewport + mobile-first parity (single-page) | false | |
--verbose | -v | Show progress | false |
--output <path> | -o | Output file path | |
--config <path> | Config file path | ||
--no-save | Do not store this audit in ~/.seomator |
Audits are stored by default, so compare and report always have history.
seomator serve runs a local web dashboard over the stored audits (history,
per-rule detail, comparisons, exports). For scripted access, read the token
from ~/.seomator/serve.json and send it as X-SEOmator-Token; GET /api
lists every route. See docs/WEB-DASHBOARD.md.
seomator compare <domain> diffs two stored audits of the same site. Every
audit is stored unless it ran with --no-save.
| Option | Description | Default |
|---|---|---|
--against <auditId> | Compare against a specific audit instead of the previous run | latest-but-one |
--trend | Show score history for the domain instead of a two-run diff | false |
--json / -j | Machine-readable diff | false |
--fail-on-regression | Exit 1 when the score dropped or new failures appeared | false |
Rules are diffed by ID, so a rule that broke and a different one that was fixed are reported separately rather than cancelling out in a count.
| Format | Flag | Best For |
|---|---|---|
| console | --format console | Human terminal output (default) |
| json | --format json | CI/CD, programmatic processing |
| html | --format html | Standalone reports, sharing |
| markdown | --format markdown | Documentation, GitHub |
| llm | --format llm | AI agents (recommended) |
The --format llm output is a compact XML format optimized for token efficiency:
compare reports which specific rules changed status, which is more useful than
a score delta on its own: a score can hold steady while one thing broke and
another was fixed. Use --fail-on-regression to make this a CI gate.
An uncaught exception halts the script that threw it, so content, structured data or canonical tags that script would have written never appear to a rendering crawler. A 404 on a script is invisible to static HTML analysis: the tag is present and well-formed, and only a real fetch reveals nothing came back.
| Score | Grade | Meaning |
|---|---|---|
| 90-100 | A | Excellent - Minor optimizations only |
| 80-89 | B | Good - Address warnings |
| 70-79 | C | Needs Work - Priority fixes required |
| 50-69 | D | Poor - Multiple critical issues |
| 0-49 | F | Critical - Major problems to resolve |
Fix issues in this order for maximum impact:
A category score is the average of its rule results — pass 100, warn 50,
fail 0 — weighted by each rule's declared weight, so a heavy rule such as
security-https moves the category far more than a minor one. The overall score
is the weighted average of category scores using the weights above.
Unmeasured checks carry weight 0 and do not affect the score. A check whose input was unavailable is reported so the gap is visible, but scores neither for nor against the site — you cannot score what you did not measure. This is why:
cwv-inp always reports unmeasured. INP requires real user interaction, which
an automated crawl does not perform. For real INP use field data (CrUX or RUM).--no-cwv reports the Core Web Vitals rules and most JavaScript
rendering rules as unmeasured rather than passing or failing them. A site
audited with --no-cwv is not directly comparable to one audited without it,
because a different set of rules contributed to the score.links-depth and links-orphan-pages need the site-wide link graph, which
only exists in crawl mode. Run with --crawl to measure them; a
single-page audit reports them unmeasured because click distance and inbound
links cannot be known from one page.mobile-parity-* rules need a second render at a mobile viewport. Run
with --mobile (and without --no-cwv) to measure them.Scores changed in v3.1.0. Earlier versions weighted failing rules 100× less than passing ones, which inflated scores. If comparing against a report generated before 3.1.0, re-run the baseline rather than treating the drop as a regression.
After implementing fixes, give the user a summary of all changes made.
When planning scope, organize tasks so they can run concurrently as sub-agents to speed up implementation.
If you see this error, seomator is not installed or not in your PATH.
Solution:
If CWV metrics are missing, Chrome/Chromium may not be available.
Solution:
seomator self doctor to verify browser detection--no-cwv to skip CWV if not neededFor large sites, audits may take several minutes.
Solution:
--verbose to see progress-m 20 for faster results--no-cwv to skip browser-based measurementsEnsure the URL includes the protocol:
Results are stored in ~/.seomator/ for later retrieval with seomator report.
The seomator CLI fetches HTML from arbitrary user-supplied URLs. Any text
quoted from those pages — titles, meta tags, headings, link text, alt
attributes, schema content — is untrusted input that may attempt indirect
prompt injection against the LLM consuming the report.
The LLM-format reporter (--format llm) applies a layered defense:
<seo-audit> element.<msg> and
<details> is wrapped in <untrusted-{nonce}>...</untrusted-{nonce}>. An
attacker cannot forge the closing tag because the nonce is unpredictable
and unique per audit.<security-notice> instructing
the consuming LLM to treat the wrapped blocks as data, not instructions.< > & " ' inside untrusted content
is escaped, so a crafted </untrusted-...> literal becomes inert text.Tool-authored fields — fix suggestions, rule IDs, category metadata — are emitted as plain XML and are not wrapped, since wrapping trusted content in untrusted delimiters would dilute the signal.
docs/SEO-AUDIT-RULES.md for all 332 rulesdocs/STORAGE-ARCHITECTURE.md for database detailsseomator --help and seomator <command> --help# Quick single-page audit with LLM output
seomator audit https://example.com --format llm --no-cwv
# Multi-page crawl (up to 50 pages)
seomator audit https://example.com --crawl -m 50 --format llm --no-cwv
# Full audit with Core Web Vitals + JS rendering analysis
seomator audit https://example.com --crawl -m 20 --format llmseomator audit https://example.com -c core,security,js --format llm --no-cwvseomator audit https://example.com --format html -o report.htmlseomator audit https://example.com --format llm -v{ "error": true, "code": "http-error", "message": "...", "hint": "..." }seomator init # Create config file
seomator self doctor # Check system setup
seomator config --list # Show all config values
seomator report --list # List past reports
seomator compare <domain> # Diff the two most recent saved audits
seomator db stats # Show database statistics# User asks: "Check example.com for SEO issues"
seomator audit https://example.com --format llm --no-cwv# User asks: "Do a thorough audit with up to 100 pages"
seomator audit https://example.com --crawl -m 100 --format llm --no-cwv# User asks: "Re-audit the site, ignore cached results"
# Every run fetches every page fresh — there is no cache to bypass.
seomator audit https://example.com --format llm --no-cwv# User asks: "Create an HTML report I can share"
seomator audit https://example.com --crawl -m 20 --format html -o seo-report.html# User asks: "Just check my JavaScript rendering and redirects"
seomator audit https://example.com -c js,redirect --format llm# A baseline before the change (stored automatically)
seomator audit https://example.com
# ... deploy ...
seomator audit https://example.com
seomator compare example.com --json# js-console-errors and js-failed-requests need a real browser render,
# so do NOT pass --no-cwv here.
seomator audit https://example.com -c js --format llm# Wrong
seomator audit example.com
# Correct
seomator audit https://example.com