agentleFS
vatsal2210vatsal2210/claude-skills/seo-measure/SKILL.md

seo-measure

Skill0 starsChanged 7 months agoMITView on GitHub

Weekly SEO + GEO measurement and learning loop. Pulls Google Search Console data, runs live AI citation checks (ChatGPT, Claude, Perplexity), compares against last week's baseline, and writes findings to per-site memory so the system compounds site-specific expertise over time. Use when the user says "measure seo", "seo weekly", "did it work", "check rankings", "am i getting cited by ai", "track seo progress", "weekly seo report", or after running seo-audit to capture the first baseline.

The file

Show its rules and text

We split this skill into the rules it gives an agent

16 rules. About 0 are common, 10 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈10

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    After seo-audit completes — capture the pre-fix baseline immediately

    line 14
  2. Distinctive:

    After shipping an SEO/GEO change — measure impact at +7 days, +14 days, +28 days

    line 16
  3. Distinctive:

    When the user asks "did it work", "is the change showing up", "am i getting more AI citations"

    line 17
  4. Distinctive:

    All of these should be stored in the site memory file on first run and reused automatically on subsequent runs.

    line 33
  5. Distinctive:

    Run these in parallel on the main thread (they're independent).

    line 37
  6. Very specific:

    Ask the user to export from Search Console → Performance → last 7 days → Export → CSV, then paste the path.

    line 53
  7. Distinctive:

    If user can't run the prompts manually, run what you can automatically (Perplexity) and flag the rest as "user action required — report …

    line 93
  8. Distinctive:

    If logs aren't accessible, skip this phase and note "server logs not available — add Vercel log forwarding or server log access to unlock …

    line 114
  9. Distinctive:

    Read the per-site memory file (see Phase 3 for path).

    line 132
  10. Distinctive:

    Never fabricate metrics: If GSC wasn't accessible, say "GSC not pulled this week" — don't invent numbers.

    line 274
  11. Very specific:

    Strong signals get promoted: When a signal crosses strong after 3+ weeks of confirmation, suggest adding it as a site-specific note in …

    line 276
  12. Distinctive:

    If the site has no memory directory yet:

    line 284
  13. Very specific:

    Create ~/.claude/projects/memory-seo/{{site_slug}}/ with empty history/, learnings.md, regressions.md

    line 286
  14. Distinctive:

    Run Phase 1 (pull what you can)

    line 288
  15. Very specific:

    Write baseline.json with Phase 1 output

    line 291
  16. Very specific:

    After seo-audit finishes its report, it should offer: *"Capture this as a baseline in seo-measure?

    line 296

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

SEO Measurement & Learning Loop

The compounding engine. An audit is a snapshot; this is the learning system. Run weekly (or after every meaningful SEO change) so the team accumulates site-specific empirical knowledge no generic expert could match.

The theoretical gap between a well-researched checklist and a 20-year SEO expert closes through one thing: measurement density on a specific site across many iterations. That's what this skill exists for.

When to Use

  • After seo-audit completes — capture the pre-fix baseline immediately
  • Weekly cadence (via /loop 7d seo-measure or /schedule) — track progress, diff vs last week
  • After shipping an SEO/GEO change — measure impact at +7 days, +14 days, +28 days
  • When the user asks "did it work", "is the change showing up", "am i getting more AI citations"

Preflight

Before running, establish:

  1. Site identifier. A canonical slug (e.g., example.com). Used for the memory file path. Ask if unclear.
  2. Live URL. Needed for AI citation + crawler simulation.
  3. GSC access mode. Three options — ask which:
    • (a) GSC API via service account — automatic, requires setup once. Recommended long-term.
    • (b) Manual CSV export — user pastes or uploads GSC "Performance" export. Works today, zero setup.
    • (c) Skip GSC this run — use only AI citation checks + crawler sim + server logs. Fine for week 1.
  4. Server log access. For crawl-budget measurement. Optional but high-value. Path to access logs if available (Vercel logs, Nginx, Cloudflare Analytics).
  5. Target keywords. Up to 10 the user cares about ranking for. Used for rank-tracking deltas.
  6. Target entities. Up to 5 "who/what" prompts for AI citation checks (site name, author name, org name, a key product, a key service). Used in Phase 2.

All of these should be stored in the site memory file on first run and reused automatically on subsequent runs.

Phase 1 — Pull the data

Run these in parallel on the main thread (they're independent).

1a. Google Search Console

Option A (API):

# Requires google-auth-httplib2 + google-api-python-client, or gsc-cli
gsc query "$SITE_URL" \
  --start-date "$(date -v-7d +%Y-%m-%d)" \
  --end-date "$(date +%Y-%m-%d)" \
  --dimensions query,page \
  --row-limit 1000 \
  --format csv > /tmp/gsc-$(date +%Y%m%d).csv

Option B (manual CSV): Ask the user to export from Search Console → Performance → last 7 days → Export → CSV, then paste the path. Parse with awk/jq/pandas-equivalent logic.

Option C (skip): proceed to 1b.

Extract:

  • Total clicks, impressions, CTR, average position — last 7 days
  • Top 20 queries by clicks
  • Top 20 pages by clicks
  • New queries (appearing this week, not last week)
  • Lost queries (in last week's data, not this week's)
  • Queries with position change ≥ 3 (either direction)
  • Coverage status (indexed / excluded / errors) — from the "Pages" report if available

1b. AI Citation Check (the GEO metric)

This is the only metric that directly proves AI-search visibility. For each target entity from preflight, query multiple AI search engines and record whether the site is cited.

Prompts to run (via WebFetch on Perplexity-style interfaces, or instruct the user to paste into ChatGPT/Claude):

For each target_entity in [site_name, author_name, org_name, product, service]:

Prompt 1: "What is {{target_entity}}?"
Prompt 2: "Who is {{target_entity}}?" (if person/org)
Prompt 3: "{{target_entity}} services" or "{{target_entity}} features"
Prompt 4: "Best {{category}} for {{use case}}" — where user expects to be cited

For each (entity, prompt, engine) tuple, record:

  • Cited? (yes/no)
  • Position in answer (early / middle / late)
  • Citation URL (which page)
  • Context (what the AI said about you)

Engines to check:

  • Perplexity (easiest — has public API via WebFetch-friendly URLs)
  • ChatGPT Search (requires user to paste — assistant can't browse as logged-in user)
  • Claude (same — ask user to paste the answer)
  • Google AI Overviews (check if SERP shows an AI Overview for the query)

If user can't run the prompts manually, run what you can automatically (Perplexity) and flag the rest as "user action required — report back next run."

1c. Server Log Analysis (if logs available)

LOG_PATH="{{user-provided}}"
SINCE=$(date -v-7d +%Y-%m-%dT%H)

# AI crawler hit frequency
for BOT in GPTBot OAI-SearchBot ChatGPT-User ClaudeBot anthropic-ai PerplexityBot Perplexity-User Google-Extended Applebot-Extended CCBot Googlebot Bingbot; do
  count=$(grep "$BOT" "$LOG_PATH" | awk -v s="$SINCE" '$1 >= s' | wc -l)
  echo "$BOT: $count hits"
done

# Most-crawled URLs by Googlebot (crawl budget signal)
grep "Googlebot" "$LOG_PATH" | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

# 404s from any bot
grep -E "Googlebot|GPTBot|ClaudeBot|PerplexityBot" "$LOG_PATH" | grep ' 404 ' | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

If logs aren't accessible, skip this phase and note "server logs not available — add Vercel log forwarding or server log access to unlock crawl-budget measurement."

1d. Live crawler re-simulation

Re-run the crawl simulation block from seo-audit Phase 5a. Compare raw HTML content-length, h1 count, JSON-LD count against last run. Any regression = 🐛.

1e. Lighthouse field data (CrUX)

# PageSpeed Insights API — field data (real users), not lab
curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=$URL&strategy=mobile&category=performance&category=seo&category=accessibility" \
  | jq '.loadingExperience.metrics'

Extract field LCP, INP, CLS percentiles. Lab Lighthouse can pass while field fails — this is the ground truth.

Phase 2 — Diff against last week

Read the per-site memory file (see Phase 3 for path). If it doesn't exist, this is the baseline run — record but don't diff.

Compute:

MetricLast weekThis weekΔVerdict
Total clicks412487+18%⬆
Total impressions8,2219,104+11%⬆
Avg position23.419.8−3.6⬆
Indexed pages4749+2⬆
Pages with Rich Results1218+6⬆
AI citations (Perplexity)2/54/5+2⬆
AI citations (ChatGPT)1/52/5+1⬆
GPTBot hits (7d)034+34⬆
ClaudeBot hits (7d)012+12⬆
Field LCP p752,840ms2,410ms−430ms⬆
Field INP p75280ms190ms−90ms⬆

Flag any regression as 🐛. Flag any improvement as a win worth attributing.

Phase 3 — Attribution (the learning step)

For every metric movement ≥ 10% (in either direction), try to explain it. Read the git log for commits to this repo in the past 7 days:

git -C {{repo-path}} log --since="7 days ago" --oneline --name-only

Cross-reference SEO-touching commits against metric changes. Examples:

  • "Added BlogPosting schema to /blog/X on Mar 5 → +214% impressions on that URL = schema working"
  • "Removed llms.txt Mar 3 → GPTBot hits dropped 80% = llms.txt was being crawled after all, put it back"
  • "Shipped per-route metadata Feb 28 → avg position on 12 pages improved by 4+ = inherited-title fix delivered"
  • "CLS regression from new hero image → LCP p75 worsened 600ms = needs priority hint + dimensions"

Attribution is inherently fuzzy. Be honest: mark each as (strong / plausible / speculative). Over time the strong signals compound.

Phase 4 — Write findings to site memory

Memory path convention:

~/.claude/projects/memory-seo/{{site-slug}}/
├── config.json              # target keywords, entities, URL, GSC mode
├── baseline.json            # first-run snapshot
├── history/
│   ├── 2026-04-12.json      # each weekly run
│   ├── 2026-04-19.json
│   └── ...
├── learnings.md             # accumulated attribution findings (strong signals only)
└── regressions.md           # every 🐛 ever logged, with date + cause if known

Each weekly snapshot (history/YYYY-MM-DD.json):

{
  "date": "2026-04-12",
  "gsc": { "clicks": 487, "impressions": 9104, "avgPosition": 19.8, "topQueries": [...], "newQueries": [...], "lostQueries": [...] },
  "ai_citations": { "perplexity": { "cited": 4, "total": 5, "details": [...] }, "chatgpt": {...}, "claude": {...} },
  "crawler_hits": { "Googlebot": 1240, "GPTBot": 34, "ClaudeBot": 12, ... },
  "field_vitals": { "lcp_p75": 2410, "inp_p75": 190, "cls_p75": 0.08 },
  "commits_this_week": [ { "sha": "...", "message": "...", "seo_relevant": true } ]
}

learnings.md — append-only knowledge base (the compounding artifact):

## {{date}}

### Strong signals
- **{{Schema type}} moves the needle on {{site_slug}}.** Added to {{route}} on {{deploy date}}. By {{measure date}}: impressions on that URL went from {{before}} → {{after}} ({{delta}}), clicks {{before}} → {{after}}. Google Rich Results Test confirmed eligibility {{n}} hours after deploy. **Rule:** prioritize {{schema type}} on this site's {{content type}} before other schema work.

- **{{AI crawler}} only started crawling after llms.txt landed.** {{N}} hits weeks 1-2, {{M}} hits week 3 (llms.txt went live {{date}}). Correlation is strong, causation uncertain. **Rule:** llms.txt is not free — it may drive AI crawler discovery on small sites even if not a ranking signal.

### Plausible signals
- Removing `images: { unoptimized: true }` correlated with −{{n}}ms LCP p75 improvement. Could also be the CDN change that shipped same day. Revisit next week.

### Regressions logged
- None this week.

## {{previous week date}}
...

Strong signals from learnings.md should be promoted into the seo-audit skill as site-specific overrides. Cross-skill knowledge transfer is the whole point.

config.json — stable per-site setup:

{
  "site_slug": "{{example.com}}",
  "url": "https://{{example.com}}",
  "repo_path": "{{/absolute/path/to/site-repo}}",
  "gsc_mode": "{{api | manual_csv | skip}}",
  "target_keywords": ["{{keyword 1}}", "{{keyword 2}}"],
  "target_entities": ["{{brand or person name}}", "{{product name}}", "{{service name}}"],
  "log_path": "{{/path/to/access.log or null}}",
  "first_run": "{{YYYY-MM-DD}}"
}

Phase 5 — Generate the weekly report

# Weekly SEO Report — {{site_slug}}
**Week of:** {{start}} to {{end}}
**Mode:** {{live / baseline}}

## Top-line movement
{{metric diff table}}

## New wins this week
- {{strong-attribution improvements}}

## Regressions (🐛)
- {{anything that got worse}}

## AI citations — GEO scoreboard
| Entity | Perplexity | ChatGPT | Claude |
| ... |

## Attributions (what worked, what didn't)
- Strong: ...
- Plausible: ...
- Speculative: ...

## New queries appearing in GSC
- {{list}}

## Lost queries
- {{list}}

## Recommendations for next week (ranked by expected ROI based on site learnings)
1. ...
2. ...
3. ...

## Memory updates
- Wrote history/{{date}}.json
- Appended {{n}} signals to learnings.md
- {{any config changes}}

Rules

  1. Never fabricate metrics. If GSC wasn't accessible, say "GSC not pulled this week" — don't invent numbers.
  2. Attribution honesty is load-bearing. Mark every claim as strong/plausible/speculative. The long-term value of learnings.md depends on signal, not noise.
  3. Strong signals get promoted. When a signal crosses strong after 3+ weeks of confirmation, suggest adding it as a site-specific note in seo-audit's "Known Anti-Patterns" or "Reference Implementations" sections.
  4. No changes to the site on a measure run. This skill reads and writes memory only. Fixes go through seo-audit → user approval.
  5. Baseline run is valid output. First run produces no diff. The snapshot itself is the deliverable — compound starts next week.
  6. Run seo-measure on a schedule, not on vibes. Recommend /loop 7d seo-measure or /schedule "0 9 * * MON" so weeks don't get skipped. Compounding requires density.
  7. Honor the traffic goal. A GEO-first user's report leads with AI citations; a Google-first user's leads with GSC. Same skill, re-ordered presentation.

First-Run Bootstrap

If the site has no memory directory yet:

  1. Create ~/.claude/projects/memory-seo/{{site_slug}}/ with empty history/, learnings.md, regressions.md
  2. Prompt for all preflight inputs and save to config.json
  3. Run Phase 1 (pull what you can)
  4. Skip Phase 2 (no last-week data)
  5. Skip Phase 3 (no commits to attribute yet)
  6. Write baseline.json with Phase 1 output
  7. Tell user: "Baseline captured. Re-run in 7 days to see first diff. Set up /loop 7d seo-measure or /schedule to automate."

Integration with seo-audit

After seo-audit finishes its report, it should offer: "Capture this as a baseline in seo-measure? (recommended — starts the compounding loop)". If yes, invoke seo-measure with the same site + findings carried over.

Pre-audit check: if learnings.md exists for this site, seo-audit should read it first and let site-specific learnings override generic priorities. That's how the system gets smarter about YOUR sites over time — not generic SEO experts, but experts on this site.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.