PluginBench
Skill
Review
Audit score 70

seo-drift

agricidaniel/claude-seo

Capture SEO baselines, detect regressions, and track on-page changes over time.

What is seo-drift?

SEO Drift Monitor acts as version control for your SEO, letting you capture snapshots of critical on-page elements (titles, meta descriptions, headings, schema, Core Web Vitals) and compare them to detect changes and regressions. Use it before and after deployments, or to investigate unexpected traffic drops.

  • Capture baseline snapshots of 13 SEO-critical elements including title, meta description, headings, schema, Open Graph tags, and Core Web Vitals
  • Compare current page state against stored baselines and trigger 17 rules across 3 severity levels (CRITICAL, WARNING, INFO)
  • Track full change history with timestamps for any URL, showing all past baselines and comparisons
  • Generate HTML drift reports summarizing all detected changes and recommended actions
  • Validate URLs with SSRF protection and store all data locally in SQLite

How to install seo-drift

npx skills add https://github.com/agricidaniel/claude-seo --skill seo-drift
Prerequisites
  • Node.js and npm installed
  • Access to the claude-seo plugin scripts directory
  • Optional: Google PageSpeed API key for Core Web Vitals capture (can skip with --skip-cwv flag)
Claude Code
Cursor
Windsurf
Cline

How to use seo-drift

  1. 1.Run `/seo drift baseline <url>` to capture the current SEO state as a known-good snapshot
  2. 2.After making changes or deploying, run `/seo drift compare <url>` to see what changed and which rules were triggered
  3. 3.Review the JSON diff report showing old/new values, severity levels, and recommended actions
  4. 4.Optionally generate an HTML report with `drift_report.py` for sharing with stakeholders
  5. 5.Use `/seo drift history <url>` to view all past baselines and comparisons for trend analysis

Use cases

Good for
  • Pre- and post-deployment SEO checks to catch breaking changes before they impact traffic
  • Investigating unexpected traffic drops by comparing current page state to historical baselines
  • Ongoing monitoring of critical pages to detect unintended SEO regressions over time
  • Auditing schema, heading structure, or meta tag changes across site updates
  • Documenting SEO state changes with timestamped snapshots for compliance or team reviews
Who it's for
  • SEO specialists and content managers monitoring site health
  • DevOps and deployment teams verifying SEO integrity after releases
  • Digital marketers investigating traffic anomalies
  • Web developers building SEO-aware CI/CD workflows

seo-drift FAQ

What SEO elements does it track?

Title tag, meta description, canonical URL, robots directives, H1/H2/H3 headings, JSON-LD schema, Open Graph tags, Core Web Vitals, HTTP status code, and content hashes for HTML and schema.

Where is the baseline data stored?

All data is stored locally in SQLite at ~/.cache/claude-seo/drift/baselines.db. No data is sent to external services.

Can I compare against a specific older baseline instead of the most recent?

Yes, use the `--baseline-id` flag with the compare command to specify which baseline snapshot to compare against.

What if Core Web Vitals data is not available?

You can skip CWV fetching with the `--skip-cwv` flag. CWV fields will be stored as null and CWV rules will not trigger during comparison.

How does it handle URL normalization?

URLs are normalized by lowercasing scheme/host, stripping default ports (80/443), sorting query parameters, removing UTM parameters, and stripping trailing slashes to ensure consistent matching.

Full instructions (SKILL.md)

Source of truth, from agricidaniel/claude-seo.


name: seo-drift description: > SEO drift monitoring: capture baselines of SEO-critical elements, detect changes, and track regressions over time. Git for SEO: baseline, diff, and track changes to your on-page SEO. Use when user says "SEO drift", "baseline", "track changes", "did anything break", "SEO regression", "compare SEO", "before and after", "monitor SEO changes", or "deployment check". user-invocable: true argument-hint: "baseline|compare|history <url>" license: MIT metadata: author: AgriciDaniel original_author: "Dan Colta (Pro Hub Challenge)" version: "2.4.1" category: seo

SEO Drift Monitor (April 2026)

Git for your SEO. Capture baselines, detect regressions, track changes over time.


Commands

CommandPurpose
/seo drift baseline <url>Capture current SEO state as a "known good" snapshot
/seo drift compare <url>Compare current page state to stored baseline
/seo drift history <url>Show change history and past comparisons

What It Captures

Every baseline records these SEO-critical elements:

ElementFieldSource
Title tagtitleparse_html.py
Meta descriptionmeta_descriptionparse_html.py
Canonical URLcanonicalparse_html.py
Robots directivesmeta_robotsparse_html.py
H1 headingsh1 (array)parse_html.py
H2 headingsh2 (array)parse_html.py
H3 headingsh3 (array)parse_html.py
JSON-LD schemaschema (array)parse_html.py
Open Graph tagsopen_graph (dict)parse_html.py
Core Web Vitalscwv (dict)pagespeed_check.py
HTTP status codestatus_codefetch_page.py
HTML content hashhtml_hash (SHA-256)Computed
Schema content hashschema_hash (SHA-256)Computed

How Comparison Works

The comparison engine applies 17 rules across 3 severity levels. Load references/comparison-rules.md for the full rule set with thresholds, recommended actions, and cross-skill references.

Severity Levels

LevelMeaningResponse Time
CRITICALSEO-breaking change, likely traffic lossImmediate
WARNINGPotential impact, needs investigationWithin 1 week
INFOAwareness only, may be intentionalReview at convenience

Storage

All data is stored locally in SQLite:

~/.cache/claude-seo/drift/baselines.db

Tables

  • baselines: Captured snapshots with all SEO elements
  • comparisons: Diff results with triggered rules and severities

URL normalization ensures consistent matching: lowercase scheme/host, strip default ports (80/443), sort query parameters, remove UTM parameters, strip trailing slashes.


Command: baseline

Captures the current state of a page and stores it.

Steps:

  1. Validate URL (SSRF protection via google_auth.validate_url())
  2. Fetch page via "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run fetch_page.py <URL>
  3. Parse HTML via "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run parse_html.py <URL>
  4. Optionally fetch CWV via "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run pagespeed_check.py <URL> (use --skip-cwv to skip)
  5. Hash HTML body and schema content (SHA-256)
  6. Store snapshot in SQLite

Execution:

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_baseline.py <url>
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_baseline.py <url> --skip-cwv

Output: JSON with baseline ID, timestamp, URL, and summary of captured elements.


Command: compare

Fetches the current page state and diffs it against the most recent baseline.

Steps:

  1. Validate URL
  2. Load most recent baseline from SQLite (or specific --baseline-id)
  3. Fetch and parse current page state
  4. Run all 17 comparison rules
  5. Classify findings by severity
  6. Store comparison result
  7. Output JSON diff report

Execution:

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_compare.py <url>
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_compare.py <url> --baseline-id 5
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_compare.py <url> --skip-cwv

Output: JSON with all triggered rules, old/new values, severity, and actions.

After comparison, offer to generate an HTML report:

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_report.py <comparison_json_file> --output drift-report.html

Command: history

Shows all baselines and comparisons for a URL.

Execution:

"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_history.py <url>
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run drift_history.py <url> --limit 10

Output: JSON array of baselines (newest first) with timestamps and comparison summaries.


Cross-Skill Integration

When drift is detected, recommend the appropriate specialized skill:

FindingRecommendation
Schema removed or modifiedRun /seo schema <url> for full validation
CWV regressionRun /seo technical <url> for performance audit
Title or meta description changedRun /seo page <url> for content analysis
Canonical changed or removedRun /seo technical <url> for indexability check
Noindex addedRun /seo technical <url> for crawlability audit
H1/heading structure changedRun /seo content <url> for E-E-A-T review
OG tags removedRun /seo page <url> for social sharing analysis
Status code changed to errorRun /seo technical <url> for full diagnostics

Error Handling

ScenarioAction
URL unreachableReport error from fetch_page.py. Do not guess state. Suggest user verify URL.
No baseline exists for URLInform user and suggest running baseline first.
SSRF blocked (private IP)Report validate_url() rejection. Never bypass.
SQLite database missingAuto-create on first use. No error.
CWV fetch fails (no API key)Store null for CWV fields. Skip CWV rules during comparison.
Page returns 4xx/5xxStill capture as baseline (status code IS a tracked field).
Multiple baselines existUse most recent unless --baseline-id specified.

Security

  • All URL fetching goes through "${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run fetch_page.py, which enforces SSRF protection (blocks private IPs, loopback, reserved ranges, GCP metadata endpoints)
  • No curl, no subprocess HTTP calls -- only the project's validated fetch pipeline
  • All SQLite queries use parameterized placeholders (?), never string interpolation
  • TLS always verified -- no verify=False anywhere in the pipeline

Typical Workflows

Pre/Post Deployment Check

/seo drift baseline https://example.com     # Before deploy
# ... deploy happens ...
/seo drift compare https://example.com      # After deploy

Ongoing Monitoring

/seo drift baseline https://example.com     # Initial capture
# ... weeks later ...
/seo drift compare https://example.com      # Check for drift
/seo drift history https://example.com      # Review all changes

Investigating a Traffic Drop

/seo drift compare https://example.com      # What changed?
/seo drift history https://example.com      # When did it change?