seo-collector — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited seo-collector (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
All responses and logs are produced in English by default. Switch to the user's language if they explicitly request it.
This skill automatically crawls a website and produces a structured site-data.json file, ready to be consumed by the seo-geo-audit skill. It replaces manual information gathering (Step 0 of the audit).
[seo-shared-context] → client-profile.md
↓
┌─────────────────────────┐
│ SEO COLLECTOR (this) │
└─────────────────────────┘
↓
site-data.json
↓
┌─────────────────────────┐
│ SEO-GEO AUDIT │
└─────────────────────────┘#### Ahrefs MCP (recommended — replaces estimates with real data)
Ahrefs MCP is available on Lite, Standard, Advanced, and Enterprise plans (from $29/month Starter). It provides real backlink data, domain rating, organic keywords, and competitor identification — all data that the collector would otherwise estimate.
If Ahrefs MCP is connected, the collector will use it to pull:
| Ahrefs endpoint | What it provides | Replaces |
|---|---|---|
domain-rating | Real DR score (0-100) + Ahrefs Rank | Estimated authority |
backlinks-stats | Total backlinks, referring domains, dofollow/nofollow | "Estimated from web search" |
broken-backlinks | Broken inbound links list | Not available without Ahrefs |
organic-keywords | Keywords the site ranks for + positions + volumes | Manual keyword search |
organic-competitors | Top organic competitors identified by Ahrefs | "Identify via web_search" |
top-pages | Pages driving the most organic traffic | Sample crawl guesswork |
batch-url-analysis | SEO metrics for multiple URLs at once | One-by-one page crawl |
brand-radar | Brand mentions across AI agents (ChatGPT, Perplexity...) | Manual GEO visibility test |
How to connect: The user provides their Ahrefs account via MCP. No API key pasting needed — MCP handles authentication.
If Ahrefs MCP is NOT connected: All metrics are estimated from observable signals via web_search and web_fetch. Clearly flag this in the output: "source": "estimated" vs "source": "ahrefs_mcp".
#### GA4 MCP (optional) If connected (github.com/googleanalytics/google-analytics-mcp), pull real organic traffic, bounce rates, conversions.
#### GSC MCP (optional) If connected (github.com/ahonn/mcp-server-gsc), pull real rankings, impressions, AI Overviews data, URL inspection.
text_content_token_limit⚠️ CRITICAL — Apply token limits to ALL `web_fetch` calls.
>
A full audit generates 25-40 web calls. Without limits, web_fetch returns entire pages (10-15K tokens each), consuming 100-175K tokens and risking context overflow before the report is generated.>
Always pass `text_content_token_limit` toweb_fetch. The SEO-relevant content (title, meta, H1, schema, headers) is concentrated in the<head>and early<body>— the rest is navigation, footer, ads, and noise.
| Fetch target | text_content_token_limit | Why this limit |
|---|---|---|
| Homepage (HTML) | 4000 | <head> + H1/H2 + first content block — enough for title, meta, schema, OG tags, CMS markers |
| robots.txt | 1000 | Always short — full AI bot rules fit easily |
| sitemap.xml | 3000 | URL count + sample URLs + lastmod — don't need every URL |
| Secondary/inner pages | 3000 | Same extraction as homepage, lighter |
| Competitor pages | 3000 | Only need title, meta, H1, schema presence |
| PageSpeed / external data | (use `web_search`, no fetch needed) | Search snippets are pre-truncated |
Example:
web_fetch: [URL] → text_content_token_limit: 4000
web_fetch: [URL]/robots.txt → text_content_token_limit: 1000Estimated savings: ~100K tokens per audit (from ~175K down to ~75K).
Before starting, test that the site is accessible:
web_fetch: [URL] (text_content_token_limit: 4000)If error (timeout, 5xx, maintenance) → note and stop. If redirect → follow and note the final URL.
Use web_fetch on the main URL (with `text_content_token_limit: 4000`) and extract:
Extract and structure: <title>, meta description, H1 (count), H2 list, canonical URL, lang attribute, hreflang tags, viewport meta, Open Graph tags, Twitter Card.
Look for markers in the HTML source: WordPress (wp-content/), Shopify (cdn.shopify.com), Webflow (webflow.com), Wix (wix.com), Next.js (__NEXT_DATA__), and others.
Fetch and parse robots.txt (with `text_content_token_limit: 1000`). For each AI bot (Googlebot, GPTBot, ChatGPT-User, PerplexityBot, ClaudeBot, anthropic-ai, Bingbot), determine if explicitly blocked, allowed, or inheriting from User-agent: *.
Fetch sitemap.xml (with `text_content_token_limit: 3000`). Extract: existence, URL, type (index or urlset), total URL count, sample URLs, last modified date.
Search for PageSpeed Insights data via web_search. Structure results for LCP, CLS, INP, FCP, TTFB — both mobile and desktop. Note data source and freshness.
If data is not found, estimate based on HTML analysis (page weight, script count, image optimization).
Analyze HTTP headers via web_fetch (with `text_content_token_limit: 2000`): HTTPS status, HSTS, Content-Security-Policy, X-Frame-Options, mixed content detection.
⚠️ CRITICAL LIMITATION: web_fetch cannot detect JavaScript-injected JSON-LD. Flag uncertainty if CMS is detected but no schema found in static HTML.Search for <script type="application/ld+json">, itemscope/itemtype (Microdata), and typeof/property (RDFa) in the HTML.
Analyze the HTML source from the homepage (and sample pages in Step 6) to detect which analytics and tracking tools are installed, and whether basic conversion tracking appears to be configured.
Search the HTML for these markers:
| Tool | Detection pattern | What it means |
|---|---|---|
| Google Analytics 4 (GA4) | gtag.js, G-XXXXXXX, googletagmanager.com/gtag | Modern analytics — good |
| Google Tag Manager (GTM) | googletagmanager.com/gtm.js, GTM-XXXXXXX | Tag container — enables event tracking without code changes |
| Universal Analytics (UA) | analytics.js, UA-XXXXXXX | Legacy — deprecated July 2024, should be migrated to GA4 |
| Facebook/Meta Pixel | fbq(, connect.facebook.net/en_US/fbevents.js | Ad tracking — indicates paid social activity |
| Hotjar / Clarity | hotjar.com, clarity.ms | Heatmaps / session recording — indicates UX focus |
| Segment | analytics.segment.com, cdn.segment.com | CDP — indicates mature tracking stack |
| Mixpanel | mixpanel.com/track, cdn.mxpnl.com | Product analytics — indicates event-level tracking |
| Matomo / Piwik | matomo.js, piwik.js | Privacy-first analytics |
| Pinterest Tag | pintrk(, s.pinimg.com | Pinterest ad tracking |
| TikTok Pixel | ttq.load, analytics.tiktok.com | TikTok ad tracking |
| LinkedIn Insight | snap.licdn.com/li.lms-analytics | LinkedIn B2B tracking |
Look for indicators that conversion events are configured:
| Signal | What to look for | Status |
|---|---|---|
| Enhanced ecommerce | purchase, add_to_cart, begin_checkout in gtag calls or dataLayer pushes | ✅/❌ |
| Form tracking | Event listeners on <form> submit, or GTM form trigger patterns | ✅/❌ |
| Scroll tracking | scroll event in gtag or GTM | ✅/❌ |
| Click tracking | click events on CTAs, outbound links | ✅/❌ |
| dataLayer present | window.dataLayer initialized | ✅/❌ |
| Consent management | Cookie banner / CMP detected (Cookiebot, OneTrust, Axeptio, Didomi) | ✅/❌ |
Check if the site preserves UTM parameters:
utm_source, utm_medium, utm_campaign patterns){
"analytics_tracking": {
"tools_detected": {
"ga4": { "present": true, "measurement_id": "G-XXXXXXX" },
"gtm": { "present": true, "container_id": "GTM-XXXXXXX" },
"ua_legacy": { "present": false },
"meta_pixel": { "present": true },
"hotjar_clarity": { "present": false, "tool": null },
"segment": { "present": false },
"mixpanel": { "present": false },
"other": []
},
"conversion_tracking": {
"ecommerce_events": false,
"form_tracking": false,
"scroll_tracking": false,
"click_tracking": false,
"datalayer_present": true,
"consent_management": { "present": true, "tool": "Axeptio" }
},
"utm_handling": {
"utm_params_detected_in_links": false,
"consistent_naming": "unknown"
},
"maturity_level": "basic|intermediate|advanced",
"issues": [
"No ecommerce conversion tracking detected",
"No heatmap/session recording tool installed"
],
"recommendations": [
"Set up GA4 ecommerce events (add_to_cart, purchase)",
"Install Hotjar or Clarity for UX insights"
]
}
}Maturity levels:
This data feeds directly into the auditor's Step 6: UX & Conversion section, replacing guesswork with detected tracking state.
Crawl 3-5 additional pages (from sitemap or navigation) (each with `text_content_token_limit: 3000`). For each, collect the same data as Step 1.
This entire step is skipped if Ahrefs MCP is not connected. All data points are then marked as "source": "estimated" in the output.Query Ahrefs MCP:
domain-rating endpoint → real DR scorebacklinks-stats → total backlinks, referring domains, dofollow ratiobroken-backlinks → list of broken inbound links (for the Implementer to generate redirects){
"ahrefs": {
"source": "ahrefs_mcp",
"domain_rating": 45,
"ahrefs_rank": 123456,
"backlinks_total": 12500,
"referring_domains": 890,
"dofollow_ratio": 0.72,
"broken_backlinks": [
{ "url_from": "https://partner.com/old-link", "url_to": "https://example.com/404-page" }
]
}
}Query Ahrefs MCP:
organic-keywords → top 50 keywords the site ranks for with positions and volumestop-pages → pages driving the most organic traffic{
"ahrefs_keywords": {
"total_organic_keywords": 2340,
"top_keywords": [
{ "keyword": "linen curtains", "position": 3, "volume": 8100, "url": "/collections/lin" },
{ "keyword": "velvet cushions", "position": 7, "volume": 3200, "url": "/collections/coussins-velours" }
],
"top_pages": [
{ "url": "/collections/rideau", "organic_traffic": 4500, "keywords_count": 120 }
]
}
}Query Ahrefs MCP:
organic-competitors → sites competing for the same keywords{
"ahrefs_competitors": [
{ "domain": "laredoute.fr", "common_keywords": 450, "competition_level": "high" },
{ "domain": "maison-monde.com", "common_keywords": 280, "competition_level": "medium" }
]
}This replaces the manual "identify competitors via web_search" step. The auditor can use these directly.
Query Ahrefs MCP:
brand-radar → brand mentions across AI agents{
"ahrefs_brand_radar": {
"source": "ahrefs_mcp",
"ai_mentions": {
"chatgpt": { "mentioned": true, "citation_count": 5 },
"perplexity": { "mentioned": true, "citation_count": 3 },
"google_ai_overview": { "mentioned": false },
"claude": { "mentioned": true, "citation_count": 1 }
},
"real_prompts_with_citations": [
{ "platform": "chatgpt", "prompt": "best linen curtains France", "cited": true }
]
}
}This is a direct replacement for the manual GEO visibility test (Step 5.6 in the auditor). Real data instead of manual searches.
web_search: "site:[domain]" — estimate indexed page count.
web_search: "[domain] bing indexed" — verify presence.
web_search: "[domain] brave search" — verify presence (critical for Claude citations).
Search for business on key directories (Yelp, TripAdvisor, Healthgrades, etc.).
Assemble all collected data into a single structured JSON file:
{
"metadata": {
"collector_version": "2.0",
"collection_date": "[ISO 8601]",
"url_audited": "[URL]",
"url_final": "[URL after redirects]",
"domain": "[extracted domain]",
"data_completeness": "high|medium|low",
"mcp_integrations": {
"ahrefs": true|false,
"ga4": true|false,
"gsc": true|false
}
},
"homepage": { "..." },
"cms_detected": "shopify|wordpress|...",
"robots_txt": { "..." },
"sitemap": { "..." },
"core_web_vitals": { "..." },
"security": { "..." },
"schema_markup": { "..." },
"analytics_tracking": { "..." },
"pages_sample": [ "..." ],
"indexation": { "..." },
"ahrefs": { "..." },
"ahrefs_keywords": { "..." },
"ahrefs_competitors": [ "..." ],
"ahrefs_brand_radar": { "..." },
"issues_summary": {
"critical": ["[list]"],
"warnings": ["[list]"],
"info": ["[list]"]
}
}Save to seo-project-[domain]/site-data.json.
If no client-profile.md exists, create a pre-filled one with detected information.
After collection, present a clear summary:
═══════════════════════════════════════════
SEO DATA COLLECTION COMPLETE — [domain]
Date: [date]
═══════════════════════════════════════════
📊 Data collected:
✅ Homepage: title, meta, H1, OG tags
✅ Robots.txt: [X] AI bots allowed / [Y] blocked
✅ Sitemap: [N] URLs found
✅ Core Web Vitals: [source]
✅ Security: HTTPS [yes/no]
✅ Schema: [types found or "check needed"]
✅ Analytics: [tools detected] | Maturity: [basic/intermediate/advanced]
✅ Sample: [N] pages analyzed
✅ Indexation: ~[N] pages on Google
[If Ahrefs MCP connected:]
✅ Ahrefs DR: [score]/100 | Referring domains: [N]
✅ Organic keywords: [N] tracked | Top position: [N]
✅ Competitors: [N] identified
✅ Brand Radar: cited by [N] AI platforms
[If Ahrefs MCP NOT connected:]
ℹ️ Backlinks & keywords: estimated (connect Ahrefs MCP for real data)
⚠️ Issues detected: [N critical] / [N warning]
[Top 3 most important issues]
📁 File generated: site-data.json
→ Ready for seo-geo-audit
Would you like to run the full audit now?| Situation | Action |
|---|---|
| Site inaccessible (timeout) | Retry after 5s. If still down → note and stop. |
| Robots.txt missing | Note exists: false, continue. |
| Sitemap missing | Check robots.txt for sitemap URL, otherwise note exists: false. |
| PageSpeed not found | Estimate via HTML analysis, note source: "estimation". |
| Page 403/401 | Note, continue with other pages. |
| Rate limiting detected | Space out requests, note in report. |
| Ahrefs MCP timeout | Note the failure, continue without Ahrefs data. Flag in output. |
| Ahrefs MCP not connected | Skip Step 7 entirely, all metrics marked "source": "estimated". |
The site-data.json file is designed to be read directly by seo-geo-audit. When the user asks to run the audit after collection:
site-data.json existsPattern 2 applied: Output-as-input chaining. The collector writes structured JSON, the auditor reads it. Loose coupling, shared files as the API layer.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.