- SEO drift is an unintended change to tracked page signals across ordinary deploys. Drift monitoring captures supported fields and compares a later fetch with the latest or a selected baseline
- 17 comparison rules across CRITICAL, WARNING, and INFO tiers detect regressions like flipped canonicals, added noindex, removed schema
- SQLite-backed, local-first: state lives in
~/.cache/claude-seo/drift/baselines.db, outside the project root - CI reporting, not a built-in severity gate: critical findings do not currently make
comparefail the process - Contributed by Dan Colta via the Pro Hub Challenge, integrated and security-hardened in Claude SEO v1.9.0
SEO drift is an unintended change to tracked page signals such as titles, canonicals, meta descriptions, schema, headings, or robots directives across ordinary deploys. A later comparison can surface the changed field and its severity for review. The finding identifies page drift, but it does not prove a ranking effect.
The Silent Killer of Organic Traffic
On-page SEO regressions are invisible at deploy time. Title tags get truncated by CMS migrations. Meta descriptions get stripped by security middleware. Schema blocks vanish during refactors. Hreflang return tags break when translations get republished. Each individual change is small. Together they erode rankings, and you only notice in Search Console weeks later when the line is already trending the wrong way.
Scheduled crawlers, rank trackers, and Search Console answer different questions and may not identify the exact deployment that changed a page. A saved baseline adds direct evidence about supported page fields, while those other sources remain useful for impact and search-performance context.
Drift monitoring closes the loop. It treats your live HTML the way Git treats your source code: baseline a known good state, diff against current, surface every meaningful change. The pattern is borrowed from software engineering for a reason. Engineers caught this problem 20 years ago with version control, linters, and CI. SEO is just late to the party.
What does drift monitoring actually check?
Every baseline captures 13 SEO-critical fields: title, meta description, canonical URL, robots meta, H1 array, H2 array, H3 array, JSON-LD schema array, Open Graph dictionary, Core Web Vitals (LCP, INP, CLS, performance score), HTTP status code, full HTML SHA-256 hash, and schema content SHA-256 hash. Comparison runs 17 rules across three severity tiers.
| Rule | Severity | Why it matters |
|---|---|---|
| Canonical URL changed | CRITICAL | Wrong canonical can deindex pages |
| Canonical URL removed | CRITICAL | Google guesses, often wrong for query params |
| Robots meta noindex added | CRITICAL | Removes pages from the index within days |
| Title tag removed | CRITICAL | Page loses an important relevance and click-through signal |
| H1 tag removed | CRITICAL | Loses primary topic signal |
| Schema JSON-LD removed | CRITICAL | Rich results disappear within hours |
| HTTP status changed to error | CRITICAL | Rankings drop within days |
| H1 text changed significantly | CRITICAL | May shift topical relevance |
| Title text changed | WARNING | Snippet display and CTR affected |
| Meta description changed | WARNING | Snippet display affected |
| Core Web Vitals regressed >20% | WARNING | Page experience signal weakens |
| Lighthouse score dropped 10+ points | WARNING | Bottleneck investigation needed |
| Schema JSON-LD content modified | WARNING | Type or property changes risk validation |
| Open Graph tags removed | WARNING | Social previews break |
| New schema JSON-LD added | INFO | Positive, but validate the new block |
| H2 structure changed | INFO | Review topical alignment |
| HTML content hash changed | INFO | Catch-all for any body content drift |
The severity tier prioritizes review. CRITICAL, WARNING, and INFO are classifications in the report, not process exit codes and not proof that a change affected search performance.
Why SQLite, and why local?
Drift state lives in ~/.cache/claude-seo/drift/baselines.db. Two tables store baselines and comparison summaries. Baselines receive numeric IDs and timestamps rather than labels. URL normalization is applied before records are matched.
Local-first by design. The SQLite history remains in the user's Claude SEO cache rather than a hosted dashboard. If a CI or another machine needs the history, provide persistent storage or an explicit baseline handoff.
Select an older record explicitly. The compare utility uses the latest baseline by default. Pass --baseline-id N through the script runtime when a specific numeric baseline is required. Record the ID and retrieval time with any comparison you share.
CI/CD Integration
The scripts can run in CI as a reporting step. The current compare utility exits nonzero only on an execution error. Critical findings are printed to stderr while the process still returns success, so a deployment needs a separate tested policy gate if findings should block the build.
# Capture a baseline /seo drift baseline https://example.com # Compare a later fetch /seo drift compare https://example.com # Select a specific stored baseline when required claude-seo run drift_compare.py https://example.com --baseline-id 5
Baseline IDs, timestamps, and local cache persistence need explicit handling in CI. Keep the produced JSON as evidence, and bind any separate blocking rule to a reviewed severity policy.
Do not treat a printed critical finding as a failed process. Parse the JSON summary in a separate tested step if your deployment policy needs to stop on a chosen finding or severity.
How does history tracking work?
Every baseline receives a timestamp and numeric ID. Run /seo drift history <url> to list stored baselines and comparison summaries for the normalized URL.
The comparison results are stored too. You do not just see that the title changed, you see exactly what the old title was, what the new title is, which rule fired, and what severity it raised. Every diff is queryable. The SQLite file is a full audit trail.
This is the part that pays back over years, not weeks. The first time a senior engineer asks "did we ever change the canonical strategy on the pricing page," the answer used to be a two-hour spelunking session through Git history and Search Console. With drift history, it is a single query. The institutional memory lives in the database, not in someone's head.
Community Contribution
Dan Colta contributed the seo-drift skill via the Pro Hub Challenge in the AI Marketing Hub Pro community. The original lives at github.com/dancolta/seo-drift-monitor and was integrated into Claude SEO v1.9.0 with permission.
During integration the implementation was security-hardened. The original used curl via subprocess for HTTP fetching, which was replaced with the validated fetch_page.py pipeline that enforces SSRF protections (blocks private IPs, loopback, reserved ranges, GCP metadata endpoints). All SQLite queries were converted to parameterized placeholders. TLS verification is mandatory everywhere. The skill ships with the same security posture as the rest of Claude SEO.
Pair With the Rest of Claude SEO
Drift catches deploy-time regressions. Audit catches systemic issues. Together: ship with confidence.
- /seo audit for periodic full-stack analysis across 9 specialized subagents
- /seo technical for crawlability and indexability monitoring
- /seo schema for structured-data detection and validation
- /seo drift for the deploy-time guardrail itself
The cross-skill integration is wired in. When drift detects a schema removal, it recommends /seo schema for full validation. When CWV regresses, it points at /seo technical. When the title changes, it suggests /seo page. Drift is the alarm, the specialized skills are the diagnostic kit.
Start Now
Start with one reachable public page and preserve the local history if you need repeat comparisons.
- Install Claude SEO from the install guide
- Capture your first baseline:
/seo drift baseline https://your-site.com - Make a change, deploy
- Run
/seo drift compare https://your-site.com - Use
--baseline-id Nthrough the script runtime when you need an older stored baseline - Add and test a separate CI policy gate only if the report should block a deploy
Start with one critical page. The homepage, the highest-traffic article, the money page. Get a baseline, run a few compares, see what the output looks like. Once the signal-to-noise feels right, expand to the rest of the site and add the CI hook.
The Bottom Line
Drift monitoring gives you a stored before-and-after comparison for supported page fields. Use that evidence alongside crawl, index, analytics, and search-performance data, and keep the current CI exit-code limitation explicit.