npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@seomator/seo-audit

v3.0.0

Published

SEOmator - Comprehensive SEO audit CLI tool with 251 rules across 20 categories

Downloads

1,046

Readme

SEOmator Audit

A comprehensive SEO audit tool with 251 audit rules across 20 categories. Available as both a command-line tool and an Electron desktop app. Analyze any website for SEO best practices, Core Web Vitals, security headers, structured data, accessibility, JavaScript rendering, redirect chains, and more.

Prefer a web interface? Try our Free SEO Audit Tool for a visual, browser-based SEO analysis.

Features

  • 251 SEO Audit Rules across 20 categories
  • Desktop App - Visual audit dashboard with real-time progress, interactive results, score history, and light/dark theme
  • CLI Tool - Single page & crawl mode with 5 output formats
  • Core Web Vitals - LCP, CLS, FCP, TTFB, INP measurement via Playwright
  • JavaScript Rendering Analysis - Compare raw vs rendered DOM for SPA/CSR sites
  • 5 Output Formats - Console, JSON, HTML, Markdown, and LLM-optimized XML
  • AI/GEO Readiness - Check semantic HTML, AI bot access, and llms.txt
  • Redirect Chain Detection - Loops, broken redirects, meta/JS redirects
  • HTML Validation - Doctype, charset, head structure, lorem ipsum detection
  • Cross-Page Analysis - Duplicate content detection, orphan pages, pagination
  • Concurrent Crawling - Fast multi-page audits with configurable concurrency
  • SQLite Storage - Persistent crawl data with compression and audit history
  • CI/CD Ready - Exit codes, JSON output, GitHub Actions & GitLab CI examples
  • TOML Configuration - Project-level settings with presets and inheritance

Installation

From npm (recommended)

# Install globally
npm install -g @seomator/seo-audit

# Run audit
seomator audit https://example.com

Note: The CLI automatically uses your system Chrome, Chromium, or Edge browser for Core Web Vitals measurement. No additional browser installation is required if you have Chrome installed.

From source

git clone https://github.com/seo-skills/seo-audit-skill.git
cd seo-audit-skill
npm install
npm run build

# Run directly
./dist/cli.js audit https://example.com

# Or link globally
npm link
seomator audit https://example.com

Desktop App

The desktop app provides a visual audit dashboard with real-time progress streaming, interactive results, score history, and light/dark theme support.

Running

# From source
git clone https://github.com/seo-skills/seo-audit-skill.git
cd seo-audit-skill
npm install
npx electron-rebuild -f -w better-sqlite3   # Compile native module for Electron
npm run electron:dev                          # Launch with hot reload

Building

npm run electron:build    # Production build
npm run electron:pack     # Build + package distributable

Desktop App Features

  • Real-time progress - Live category-by-category progress as the audit runs
  • Score dashboard - Overall score circle, category grid, and issues summary table
  • Interactive results - Expandable rule cards with rule descriptions, affected items, page URL badges, and inline fix suggestions
  • Filter & navigate - Filter by status (All/Failures/Warnings/Passed), click issues to jump to details
  • Score history - Track audit scores over time per domain with trend charts
  • Light/dark theme - Follows your system preference or toggle manually

Quick Start (CLI)

# Basic audit
seomator audit https://example.com

# Skip Core Web Vitals (faster)
seomator audit https://example.com --no-cwv

# Audit specific categories
seomator audit https://example.com -c core,security,perf

# JSON output (for CI/CD or parsing)
seomator audit https://example.com --format json

# HTML report
seomator audit https://example.com --format html -o report.html

# LLM-optimized output (pipe to Claude)
seomator audit https://example.com --format llm --no-cwv | claude "analyze and prioritize fixes"

# Crawl multiple pages
seomator audit https://example.com --crawl --max-pages 20

# Full options
seomator audit https://example.com --crawl -m 50 --concurrency 5 --timeout 60000 --format json -o results.json

Commands

seomator audit <url>

Run SEO audit on a URL.

| Option | Alias | Description | Default | |--------|-------|-------------|---------| | --format <type> | -f | Output format: console, json, html, markdown, llm | console | | --output <path> | -o | Output file path | - | | --categories <list> | -c | Comma-separated categories to audit | All | | --json | -j | Output as JSON (deprecated, use --format json) | false | | --crawl | - | Enable crawl mode for multiple pages | false | | --max-pages <n> | -m | Maximum pages to crawl | 10 | | --concurrency <n> | - | Concurrent requests | 3 | | --timeout <ms> | - | Request timeout in milliseconds | 30000 | | --no-cwv | - | Skip Core Web Vitals measurement | false | | --verbose | -v | Show progress | false | | --refresh | -r | Ignore cache, fetch fresh | false | | --resume | - | Resume interrupted crawl | false | | --config <path> | - | Config file path | - | | --save | - | Save report to .seomator/reports/ | false |

seomator init

Create a seomator.toml config file.

seomator init                    # Interactive setup
seomator init -y                 # Use defaults
seomator init --preset blog      # Blog preset
seomator init --preset ecommerce # E-commerce preset
seomator init --preset ci        # Minimal CI config

seomator crawl <url>

Crawl website without running analysis. Saves data for later analysis with seomator analyze.

seomator crawl https://example.com -m 20
seomator crawl https://example.com --refresh
seomator crawl https://example.com --resume

seomator analyze [crawl-id]

Run rules on stored crawl data.

seomator analyze                           # Analyze latest crawl
seomator analyze --latest --save           # Analyze and save
seomator analyze 2026-01-23-abc123         # Specific crawl

seomator report [query]

View and query past reports.

seomator report --list                     # List all reports
seomator report --project mysite           # Filter by project

seomator config [key] [value]

View or modify configuration.

seomator config --list                     # Show all config
seomator config crawler.max_pages 50       # Set value
seomator config validate                   # Validate config

seomator db

Database management.

seomator db migrate              # Migrate JSON to SQLite
seomator db migrate --dry-run    # Preview migration
seomator db stats -v             # Database statistics
seomator db restore              # Rollback migration

seomator self doctor

Check system setup and dependencies.

seomator self doctor -v          # Verbose diagnostics

Exit Codes

| Code | Meaning | |------|---------| | 0 | Audit passed (score >= 70) | | 1 | Audit failed (score < 70) | | 2 | Error occurred |

Categories & Rules (251 total)

Core (19 rules) - 12% weight

| Rule | Description | |------|-------------| | core-title-present | <title> tag exists | | core-title-length | Title should be 30-60 characters | | core-description-present | Meta description exists | | core-description-length | Description should be 120-160 characters | | core-canonical-present | Canonical URL exists | | core-canonical-valid | Canonical URL is valid absolute URL | | core-viewport-present | Viewport meta tag exists | | core-favicon-present | Favicon link exists | | core-h1-present | At least one H1 exists | | core-h1-single | Only one H1 exists | | core-canonical-header | HTML canonical and Link header match | | core-nosnippet | Detects nosnippet/max-snippet:0 directives | | core-robots-meta | Checks noindex/nofollow directives | | core-title-unique | Titles should be unique site-wide | | core-canonical-conflicting | HTML and header canonicals should not conflict | | core-canonical-to-homepage | Canonical should not always point to homepage | | core-canonical-http-mismatch | Canonical protocol should match page protocol | | core-canonical-loop | Detects circular canonical chains | | core-canonical-to-noindex | Canonical should not point to noindexed page |

Performance (22 rules) - 12% weight

| Rule | Description | |------|-------------| | cwv-lcp | Largest Contentful Paint (<2.5s pass, >4s fail) | | cwv-cls | Cumulative Layout Shift (<0.1 pass, >0.25 fail) | | cwv-inp | Interaction to Next Paint (<200ms pass, >500ms fail) | | cwv-ttfb | Time to First Byte (<800ms pass, >1800ms fail) | | cwv-fcp | First Contentful Paint (<1.8s pass, >3s fail) | | perf-dom-size | DOM should have <1500 nodes | | perf-css-file-size | CSS files should be reasonably sized | | perf-font-loading | Font-display: swap should be used | | perf-preconnect | Preconnect hints for third-party origins | | perf-render-blocking | Scripts should use async/defer | | perf-lazy-above-fold | Above-fold images should not be lazy-loaded | | perf-lcp-hints | LCP element should be preloaded | | perf-text-compression | Responses should use gzip/Brotli compression | | perf-brotli | Prefer Brotli over gzip for better compression | | perf-cache-policy | Static assets should have cache headers | | perf-minify-css | CSS should be minified | | perf-minify-js | JavaScript should be minified | | perf-response-time | Server response time should be <200ms | | perf-http2 | Site should serve over HTTP/2 | | perf-page-weight | Total page size should be <3MB | | perf-js-file-size | Individual JS files should be <500KB | | perf-video-for-animations | Use <video> instead of animated GIFs |

Links (19 rules) - 8% weight

| Rule | Description | |------|-------------| | links-broken-internal | Internal links should return 200 | | links-external-valid | External links should be reachable | | links-internal-present | Page should have internal links | | links-nofollow-appropriate | nofollow used appropriately | | links-anchor-text | Anchor text should be descriptive | | links-depth | Page depth should be ≤3 from homepage | | links-dead-end-pages | Pages should have outgoing internal links | | links-https-downgrade | HTTPS pages should not link to HTTP | | links-external-count | Warn if >100 external links | | links-invalid-links | No empty, javascript:, or malformed hrefs | | links-tel-mailto | Valid tel: and mailto: link formats | | links-redirect-chains | Links should not go through redirects | | links-orphan-pages | Pages should have incoming links | | links-localhost | No localhost/127.0.0.1 URLs in production | | links-local-file | No file:// protocol links | | links-broken-fragment | Fragment links should match element IDs | | links-excessive | Limit internal links per page | | links-onclick | No onclick-based navigation instead of <a> tags | | links-whitespace-href | No whitespace in href attributes |

Images (14 rules) - 8% weight

| Rule | Description | |------|-------------| | images-alt-present | All images should have alt attribute | | images-alt-quality | Alt text should be descriptive | | images-dimensions | Images should have width/height | | images-lazy-loading | Below-fold images should use lazy loading | | images-modern-format | Use WebP/AVIF formats | | images-size | Images should be <200KB | | images-responsive | Use srcset for responsive images | | images-broken | Images should not return 404 | | images-figure-captions | Figure elements should have figcaption | | images-filename-quality | Use descriptive filenames | | images-inline-svg-size | Inline SVGs should be <5KB | | images-picture-element | Picture elements must have img fallback | | images-alt-length | Alt text should be under 125 characters | | images-background-seo | Content images should use <img>, not CSS background |

Security (16 rules) - 8% weight

| Rule | Description | |------|-------------| | security-https | Site should use HTTPS | | security-https-redirect | HTTP should redirect to HTTPS | | security-hsts | Strict-Transport-Security header | | security-csp | Content-Security-Policy header | | security-x-frame | X-Frame-Options header | | security-x-content-type | X-Content-Type-Options: nosniff | | security-external-links | External target="_blank" links have noopener/noreferrer | | security-form-https | Form actions use HTTPS | | security-mixed-content | No HTTP resources on HTTPS pages | | security-permissions-policy | Permissions-Policy header present | | security-referrer-policy | Referrer-Policy header present | | security-leaked-secrets | No exposed API keys or credentials | | security-password-http | Login forms served over HTTPS only | | security-protocol-relative | No protocol-relative URLs (//example.com) | | security-ssl-expiry | SSL certificate not near expiration | | security-ssl-protocol | TLS 1.2+ required; no TLS 1.0/1.1 |

Technical SEO (13 rules) - 7% weight

| Rule | Description | |------|-------------| | technical-robots-txt-exists | robots.txt should return 200 | | technical-robots-txt-valid | robots.txt should have valid syntax | | technical-sitemap-exists | sitemap.xml should exist | | technical-sitemap-valid | Sitemap should have valid XML structure | | technical-url-structure | URL should use hyphens, lowercase | | technical-trailing-slash | Consistent trailing slash usage | | technical-www-redirect | www/non-www should redirect to one version | | technical-404-page | Custom 404 page should exist | | technical-soft-404 | Soft 404 pages should return proper 404 status | | technical-server-error | No 5xx server errors | | technical-4xx-non-404 | No 400, 403, 410 client errors | | technical-timeout | Pages should respond within timeout | | technical-bad-content-type | Content-Type header matches actual content |

Crawlability (18 rules) - 5% weight

| Rule | Description | |------|-------------| | crawl-schema-noindex-conflict | Schema.org and noindex should not conflict | | crawl-pagination-canonical | Paginated pages should self-canonicalize | | crawl-sitemap-domain | Sitemap URLs should match host domain | | crawl-noindex-in-sitemap | Noindexed pages should not be in sitemap | | crawl-indexability-conflict | robots.txt and noindex should not both block | | crawl-canonical-redirect | Canonical should not point through redirects | | crawl-sitemap-url-limit | Sitemap should have <50,000 URLs | | crawl-sitemap-size-limit | Sitemap should be <50MB | | crawl-sitemap-duplicate-urls | No duplicate URLs in sitemap | | crawl-sitemap-orphan-urls | Sitemap URLs should be linked internally | | crawl-blocked-resources | Critical resources not blocked by robots.txt | | crawl-crawl-delay | Excessive Crawl-delay slows indexing | | crawl-sitemap-in-robotstxt | robots.txt should reference sitemap | | crawl-pagination-broken | Pagination links should not be broken | | crawl-pagination-loop | No circular pagination chains | | crawl-pagination-sequence | No gaps in pagination sequence | | crawl-pagination-noindex | Paginated pages should not be noindexed | | crawl-pagination-orphaned | Paginated pages should be linked from content |

Structured Data (13 rules) - 5% weight

| Rule | Description | |------|-------------| | schema-present | JSON-LD or microdata should exist | | schema-valid | JSON-LD should be valid JSON | | schema-type | @type field should be present | | schema-required-fields | Required fields for schema type | | schema-article | Validates Article schema properties | | schema-breadcrumb | Checks BreadcrumbList on non-homepage | | schema-faq | Validates FAQPage schema structure | | schema-local-business | Validates LocalBusiness for local SEO | | schema-organization | Validates Organization schema | | schema-product | Validates Product schema for e-commerce | | schema-review | Validates Review/AggregateRating schema | | schema-video | Validates VideoObject schema | | schema-website-search | Checks WebSite sitelinks searchbox |

JavaScript Rendering (13 rules) - 5% weight

| Rule | Description | |------|-------------| | js-rendered-title | Title present in rendered DOM | | js-rendered-description | Meta description present in rendered DOM | | js-rendered-h1 | H1 present in rendered DOM | | js-rendered-canonical | Canonical present in rendered DOM | | js-canonical-mismatch | Canonical matches between raw and rendered HTML | | js-noindex-mismatch | Noindex consistent between raw and rendered HTML | | js-title-modified | Title not changed by JavaScript | | js-description-modified | Description not changed by JavaScript | | js-h1-modified | H1 not changed by JavaScript | | js-rendered-content | Main content present without JavaScript dependency | | js-rendered-links | Navigation links present without JavaScript | | js-blocked-resources | Critical JS not blocked by robots.txt | | js-ssr-check | Server-side rendering detected |

Accessibility (12 rules) - 4% weight

| Rule | Description | |------|-------------| | a11y-aria-labels | Interactive elements have accessible names | | a11y-color-contrast | Color contrast issues detected | | a11y-focus-visible | Focus indicator styles present | | a11y-form-labels | Form inputs have associated labels | | a11y-heading-order | Heading levels don't skip | | a11y-landmark-regions | Proper landmark regions (main, nav, footer) | | a11y-link-text | Descriptive link text (no "click here") | | a11y-skip-link | Skip-to-content link for keyboard navigation | | a11y-table-headers | Data tables have proper headers | | a11y-touch-targets | Minimum 44x44px touch target sizing | | a11y-video-captions | Videos have captions or transcripts | | a11y-zoom-disabled | Viewport doesn't disable user zoom |

Content (17 rules) - 5% weight

| Rule | Description | |------|-------------| | content-word-count | Page should have 300+ words | | content-reading-level | Flesch-Kincaid reading level check | | content-keyword-stuffing | Detects excessive keyword repetition | | content-article-links | Checks link-to-content ratio | | content-broken-html | Detects malformed HTML structure | | content-meta-in-body | Meta tags should be in head | | content-mime-type | Validates Content-Type header | | content-duplicate-description | Descriptions should be unique site-wide | | content-heading-hierarchy | Proper heading hierarchy (H1>H2>H3) | | content-heading-length | Headings should be 10-70 characters | | content-heading-unique | Headings should be unique | | content-text-html-ratio | Text-to-HTML ratio should be >10% | | content-title-same-as-h1 | Title and H1 should differ | | content-title-pixel-width | Title pixel width for SERP display (<580px) | | content-description-pixel-width | Description pixel width for SERP (<920px) | | content-duplicate-exact | Detects exact duplicate content across pages | | content-duplicate-near | Detects near-duplicate content via simhash |

Social (9 rules) - 3% weight

| Rule | Description | |------|-------------| | social-og-title | og:title meta tag | | social-og-description | og:description meta tag | | social-og-image | og:image with valid URL | | social-og-image-size | og:image dimensions (1200x630) | | social-twitter-card | twitter:card meta tag | | social-og-url | og:url meta tag | | social-og-url-canonical | og:url matches canonical | | social-share-buttons | Social share buttons present | | social-social-profiles | Social profile links present |

E-E-A-T (14 rules) - 3% weight

| Rule | Description | |------|-------------| | eeat-about-page | About page exists | | eeat-affiliate-disclosure | Affiliate links have disclosure | | eeat-author-byline | Author attribution present | | eeat-author-expertise | Author credentials/bio present | | eeat-citations | Links to authoritative sources | | eeat-contact-page | Contact page exists | | eeat-content-dates | Publication/modification dates present | | eeat-disclaimers | YMYL content has disclaimers | | eeat-editorial-policy | Editorial policy page exists | | eeat-physical-address | Business address present | | eeat-privacy-policy | Privacy policy link present | | eeat-terms-of-service | Terms of service link present | | eeat-trust-signals | Trust badges, reviews, certifications | | eeat-ymyl-detection | YMYL content detection |

URL Structure (14 rules) - 3% weight

| Rule | Description | |------|-------------| | url-slug-keywords | URL slug contains keywords | | url-stop-words | URL should not have stop words | | url-uppercase | URLs should be lowercase | | url-underscores | Use hyphens, not underscores | | url-double-slash | No consecutive slashes in path | | url-spaces | No spaces in URL | | url-non-ascii | No non-ASCII characters in URL | | url-length | URL should be under 2048 characters | | url-repetitive-path | No repetitive path segments | | url-parameters | Excessive query parameters | | url-session-ids | No session IDs in URL | | url-tracking-params | Tracking parameters should use canonical | | url-internal-search | Internal search URLs should be noindexed | | url-http-https-duplicate | HTTP/HTTPS versions should canonicalize |

Redirects (8 rules) - 3% weight

| Rule | Description | |------|-------------| | redirect-meta-refresh | No <meta http-equiv="refresh"> redirects | | redirect-javascript | No JavaScript-based redirects | | redirect-http-refresh | No HTTP Refresh header redirects | | redirect-loop | No circular redirect chains | | redirect-type | Prefer 301 over 302 for permanent moves | | redirect-broken | Redirects should not lead to errors | | redirect-resource | No redirects on CSS/JS/image resources | | redirect-case-normalization | Redirect uppercase URLs to lowercase |

Mobile (5 rules) - 2% weight

| Rule | Description | |------|-------------| | mobile-font-size | Minimum 16px body text | | mobile-horizontal-scroll | No horizontal scrolling | | mobile-interstitials | No intrusive interstitials | | mobile-viewport-width | No fixed viewport width | | mobile-multiple-viewports | Single viewport meta tag |

Internationalization (10 rules) - 2% weight

| Rule | Description | |------|-------------| | i18n-lang-attribute | HTML lang attribute present | | i18n-hreflang | Hreflang tags for multilingual sites | | i18n-hreflang-return-links | Hreflang targets link back to source | | i18n-hreflang-to-noindex | Hreflang should not point to noindexed pages | | i18n-hreflang-to-non-canonical | Hreflang should point to canonical URLs | | i18n-hreflang-to-broken | Hreflang should not point to broken URLs | | i18n-hreflang-to-redirect | Hreflang should not point through redirects | | i18n-hreflang-conflicting | No duplicate hreflang for same language | | i18n-hreflang-lang-mismatch | Page language matches hreflang code | | i18n-hreflang-multiple-methods | Use single hreflang method |

HTML Validation (9 rules) - 2% weight

| Rule | Description | |------|-------------| | htmlval-missing-doctype | <!DOCTYPE html> must be present | | htmlval-missing-charset | <meta charset> must be in head | | htmlval-invalid-head | Only metadata elements in <head> | | htmlval-noscript-in-head | <noscript> should be in body | | htmlval-multiple-heads | Single <head> element only | | htmlval-size-limit | HTML should be under 5MB | | htmlval-lorem-ipsum | No placeholder lorem ipsum text | | htmlval-multiple-titles | Single <title> tag only | | htmlval-multiple-descriptions | Single meta description only |

AI/GEO Readiness (5 rules) - 2% weight

| Rule | Description | |------|-------------| | geo-semantic-html | Uses semantic HTML elements | | geo-content-structure | Proper heading hierarchy and lists | | geo-ai-bot-access | AI crawlers (GPTBot, ClaudeBot) not blocked | | geo-llms-txt | /llms.txt file for AI discovery | | geo-schema-drift | JSON-LD matches visible content |

Legal Compliance (1 rule) - 1% weight

| Rule | Description | |------|-------------| | legal-cookie-consent | Cookie consent banner present |

Configuration

Create a seomator.toml config file with seomator init:

[project]
name = "my-website"
domains = ["example.com", "www.example.com"]

[crawler]
max_pages = 100
concurrency = 3
timeout_ms = 30000
respect_robots = true
delay_ms = 100
include = []
exclude = ["/admin/**", "/api/**"]
drop_query_prefixes = ["utm_", "gclid", "fbclid"]

[rules]
enable = ["*"]
disable = ["perf-inp"]  # Supports wildcards: "core-*"

[output]
format = "console"  # console, json, html, markdown, llm

Config priority (highest to lowest):

  1. CLI arguments
  2. Local ./seomator.toml
  3. Parent directory configs
  4. Global ~/.seomator/config.toml
  5. Built-in defaults

Output Formats

| 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, piping to Claude |

Terminal Output

╔══════════════════════════════════════════════════════════════╗
║  SEOmator Audit Report                                      ║
╚══════════════════════════════════════════════════════════════╝

URL:       https://example.com
Score:     88/100  [A]

┌──────────────────────────┬───────┬────────┬──────────┬────────┐
│ Category                 │ Score │ Passed │ Warnings │ Failed │
├──────────────────────────┼───────┼────────┼──────────┼────────┤
│ Core                     │ 97    │ 18     │ 1        │ 0      │
│ Performance              │ 85    │ 18     │ 3        │ 1      │
│ JavaScript Rendering     │ 100   │ 13     │ 0        │ 0      │
│ ...                      │       │        │          │        │
└──────────────────────────┴───────┴────────┴──────────┴────────┘

JSON Output

{
  "url": "https://example.com",
  "overallScore": 88,
  "categoryResults": [
    {
      "categoryId": "core",
      "score": 97,
      "passCount": 18,
      "warnCount": 1,
      "failCount": 0,
      "results": [...]
    }
  ],
  "timestamp": "2026-01-23T16:00:00.000Z",
  "crawledPages": 1
}

CI/CD Integration

GitHub Actions

name: SEO Audit

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install SEOmator
        run: npm install -g @seomator/seo-audit

      - name: Install Playwright browsers
        run: npx playwright install chromium

      - name: Run SEO Audit
        run: seomator audit https://your-staging-url.com --format json -o seo-report.json

      - name: Upload Report
        uses: actions/upload-artifact@v4
        with:
          name: seo-report
          path: seo-report.json

GitLab CI

seo-audit:
  image: node:20
  script:
    - npm install -g @seomator/seo-audit
    - npx playwright install chromium
    - seomator audit https://your-staging-url.com --format json -o seo-report.json
  artifacts:
    paths:
      - seo-report.json

Programmatic Usage

import { Auditor, createAuditor } from '@seomator/seo-audit';

const auditor = createAuditor({
  categories: ['core', 'security', 'perf'],
  measureCwv: true,
  onCategoryComplete: (categoryId, name, result) => {
    console.log(`${name}: ${result.score}/100`);
  }
});

const result = await auditor.audit('https://example.com');
console.log(`Overall Score: ${result.overallScore}`);

Claude Code Skill

Use SEOmator directly in Claude Code as an AI skill for automated SEO auditing.

Setup

npx skills add seo-skills/seo-audit-skill

Usage

"Run an SEO audit on https://example.com"
"Audit https://mysite.com and tell me what to fix first"
"Check SEO health of https://example.com with 20-page crawl"

Requirements

  • Node.js 18+ (uses native fetch API)
  • Playwright (for Core Web Vitals and JS rendering analysis)

After installing, run npx playwright install chromium to install the browser for CWV measurement.

For the desktop app, better-sqlite3 must be compiled for Electron's Node version:

npx electron-rebuild -f -w better-sqlite3

License

MIT