seo-drift
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", "
By agricidaniel · 4,287 installs
npx skills add agricidaniel/claude-seo --skill seo-drift
Source repository · Upstream listing
SEO Drift Monitor (April 2026)
Git for your SEO. Capture baselines, detect regressions, track changes over time.
Commands
Command Purpose
/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:
Element Field Source
Title tag title parse html.py
Meta description meta description parse html.py
Canonical URL canonical parse html.py
Robots directives meta robots parse html.py
H1 headings h1 (array) parse html.py
H2 headings h2 (array) parse html.py
H3 headings h3 (array) parse html.py
JSON LD schema schema (array) parse html.py
Open Graph tags open graph (dict) parse html.py
Core Web Vitals cwv (dict) pagespeed check.py
HTTP status code status code fetch page.py
HTML content hash html hash (SHA 256) Computed
Schema content hash schema 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
Level Meaning Response Time
CRITICAL SEO breaking change, likely traffic loss Immediate
WARNING Potential impact, needs investigation Within 1 week
INFO Awareness only, may be intentional Review at convenience
Storage
All data is stored locally in SQLite:
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:
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:
Output: JSON with all triggered rules, old/new values, severity, and actions.
After comparison, offer to generate an HTML report:
Command: history
Shows all baselines and comparisons for a URL.
Execution:
Output: JSON array of baselines (newest first) with timestamps and comparison summaries.
Cross Skill Integration
When drift is detected, recommend the appropriate specialized skill:
Finding Recommendation
Schema removed or modified Run /seo schema <url for full validation
CWV regression Run /seo technical <url for performance audit
Title or meta description changed Run /seo page <url for content analysis
Canonical changed or removed Run /seo technical <url for indexability check
Noindex added Run /seo technical <url for crawlability audit
H1/heading structure changed Run /seo content <url for E E A T review
OG tags removed Run /seo page <url for social sharing analysis
Status code changed to error Run /seo technical <url for full diagnostics
Error Handling
Scenario Action
URL unreachable Report error from fetch page.py . Do not guess state. Suggest user verify URL.
No baseline exists for URL Inform user and suggest running baseline first.
SSRF blocked (private IP) Report validate url() rejection. Never bypass.
SQLite database missing Auto 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/5xx Still capture as baseline (status code IS a tracked field).
Multiple baselines exist Use 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
Ongoing Monitoring
Investigating a Traffic Drop