seo-local — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited seo-local (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
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.
Example output: examples/seo-local-sweetgreen-com-20260514/LOCAL-SEO-REPORT.md
Score a local business's website against the signals that drive local-pack and "near me" visibility — GBP integration on the page, NAP consistency, on-page local intent, citation footprint on Tier-1 directories, review-platform presence, and local-pack rank for the business's primary keywords. Deliverable is one prioritised fix list, anchored in observable signals.
Adapted fromAgriciDaniel/claude-seo'sseo-localskill (MIT). Concept and dimension structure mirror the upstream; backend rewired to SE Ranking + Firecrawl + Google APIs. DataForSEO Maps geo-grid and Business Listings checks from the upstream are dropped (no equivalent backend) — see "Limitations" in the deliverable.
WebFetch tool available (used for sense-check fallback when Firecrawl is unavailable)."dentist Brooklyn", "plumber near me"), (c) target country and ideally city/region for local-pack scoping. Optional: GBP listing URL, Yelp/Trustpilot URLs for review scraping.skills/seo-firecrawl/references/preflight.md for the canonical 3-stage preflight (credit balance, Firecrawl availability, Google APIs). Skill-specific notes:<title> + <h1> of the homepage; if still ambiguous, ask the user before continuing.tel: / address element extraction become best-effort prose inspection. Pass --no-firecrawl to force WebFetch-only.skills/seo-google/references/cross-skill-integration.md for the full enrichment contract./contact + footer prose (WebFetch markdown is enough for this).areaServed in schema without address.streetAddress.LOCAL-SEO-REPORT.md "Snapshot"./menu, /practice-areas, /listings, /inventory), <title>, page prose, infer one of: Restaurant / Healthcare / Legal / Home Services / Real Estate / Automotive / Generic.references/local-citation-sources.md for the vertical's Tier-1 directories.mcp__firecrawl-mcp__firecrawl_scrape (with formats: ["rawHtml"])/contact (or whichever page has the most local intent).rawHtml extract:<iframe src="https://www.google.com/maps/embed?...">) — record place ID if present.aggregateRating JSON-LD block (presence is the strongest signal that the site wants stars in SERPs).<a href="tel:..."> elements.<a href> to https://g.page/... or https://maps.app.goo.gl/... or https://www.google.com/maps/place/....tel: link in some renderings but loses iframes and JSON-LD. Mark Maps embed / aggregateRating / GBP profile-link detection as (skipped — Firecrawl required).mcp__firecrawl-mcp__firecrawl_scrape on homepage + 5 sample pages/contact, /about, plus 2 service or location pages (pick from sitemap or top traffic pages).tel: href + display format), business name (logo alt, footer, schema name).<script type="application/ld+json"> block. Pull name, address.streetAddress, address.addressLocality, address.addressRegion, address.postalCode, telephone.nap-inconsistencies.csv.nap-inconsistencies.csv is empty after the scan, write nap-inconsistencies.csv as a one-line file with header only and note "NAP consistent across {n} pages and schema" in LOCAL-SEO-REPORT.md.DATA_getSerpResults with country/region filtersDATA_getSerpResults with the user's country and the most specific region/city the API supports (use DATA_getSerpLocations first to confirm a valid location code if the user supplied a city).keyword,country,location,local_pack_present,target_in_pack,target_pack_position,target_organic_position,top_pack_competitor_1,top_pack_competitor_2,top_pack_competitor_3).mcp__firecrawl-mcp__firecrawl_scrape on user-provided review URLshttps://www.google.com/maps/place/...), Yelp business URL, Trustpilot business URL, BBB profile URL.formats: ["rawHtml"]. From the parsed DOM, extract: total review count, average rating, date of most recent review (review velocity proxy), count of owner responses on the most recent 10 reviews.LOCAL-SEO-REPORT.md: "Review platforms: not provided. To audit review health, re-run with --reviews 'gbp_url,yelp_url,trustpilot_url'." Don't try to discover them — review-URL discovery is a different problem (and the Maps API path is the one we don't have).DATA_getAuditReport (existing audit) + DATA_getIssuesByUrl on the homepageLocalBusiness JSON-LD.aggregateRating, malformed address).seo-schema for paste-ready LocalBusiness markup with the correct industry subtype" — that's seo-schema's job and reimplementing it here would duplicate work.8b. GSC local query performance (only if google-api.json is present, tier ≥ 1)
python3 scripts/gsc_query.py --property "{config.default_property}" --days 28 --json
near me, contains a city/region known for the business, or ends in a place-name. Surface top 10 by impressions.LOCAL-SEO-REPORT.md "Top fixes" with the GSC numbers as supporting evidence.skills/seo-google/references/cross-skill-integration.md for failure modes.8c. GA4 organic by landing page (only if google-api.json is present, tier ≥ 2)
python3 scripts/ga4_report.py --report top-pages --days 28 --json
WebSearch (no API key cost)references/local-citation-sources.md), check whether the business has a listing using site:{directory} "{business_name}" queries via WebSearch.LOCAL-SEO-REPORT.md "Citations" section: detected / not detected per directory, plus the URL of the listing if found.LOCAL-SEO-REPORT.mdCreate a folder seo-local-{domain-slug}-{YYYYMMDD}/ with:
seo-local-{domain-slug}-{YYYYMMDD}/
├── LOCAL-SEO-REPORT.md (PRIMARY: verdict, scores, top fixes, limitations)
├── local-keywords.csv (load-bearing: per-keyword local-pack + organic positions)
├── nap-inconsistencies.csv (load-bearing: only emitted if discrepancies found)
└── evidence/
├── 01-homepage-snapshot.md (Firecrawl raw HTML extracts: NAP, schema, GBP signals)
├── 02-nap-page-samples.md (per-page NAP extracts across 5 sample URLs)
├── 03-serp-context.md (raw DATA_getSerpResults per keyword)
├── 04-reviews.md (per-platform review-page snapshots, only if user provided URLs)
└── 05-citation-sample.md (raw WebSearch results per directory check)LOCAL-SEO-REPORT.md follows this shape:
# Local SEO Report: {domain}
> Snapshot dated {YYYY-MM-DD} · Country: {country} · Region: {region} · Primary keyword: "{keyword}"
## Snapshot
- Business type: {Brick-and-Mortar | SAB | Hybrid}
- Industry vertical: {Restaurant | Healthcare | Legal | Home Services | Real Estate | Automotive | Generic}
- Pages sampled for NAP: {n}
- Local keywords tracked: {n}
- Local pack present on {n}/{m} keywords; target in pack on {p}/{m}
- Review platforms audited: {Google, Yelp, ... | not provided}
- GSC last 28d local-intent queries: {n} queries / {clicks} clicks / {impressions} impressions *(or `not configured`)*
## Verdict: {STRONG | NEEDS WORK | WEAK}
{One-sentence summary anchored in dimension scores below}
## Dimension scores (0–10)
| Dimension | Score | Top finding |
|---|---|---|
| GBP integration on page | {n}/10 | {one-line} |
| NAP consistency | {n}/10 | {one-line} |
| Local on-page (title/H1/contact/service pages) | {n}/10 | {one-line} |
| Local-pack rank | {n}/10 | {one-line} |
| Reviews & citations | {n}/10 | {one-line} |
| **Composite** | {n}/10 | — |
## Top fixes
### Critical
1. {Specific fix anchored in a finding above. Example: "NAP discrepancy: footer shows '(212) 555-1234' but JSON-LD shows '+1-212-555-9999'. Pick one canonical phone, fix the wrong one." Cite the page/schema source.}
### High
- {fix}
### Medium
- {fix}
### Low
- {fix}
## Local-pack rank summary
- "{keyword 1}": local pack {present/absent}, target {in pack at #n / not in pack}, organic position {n}.
- "{keyword 2}": …
- (Full data: `local-keywords.csv`)
## Reviews health (if audited)
- Google: {n} reviews, {rating} avg, last review {n} days ago, owner response rate {p}%.
- Yelp: …
- Trustpilot: …
## Citation sample
- Google Business: {detected / not detected via site:google.com "..." search}
- Yelp: …
- Facebook: …
- BBB: …
- Apple Business Connect: …
- Bing Places: …
- {vertical-specific 1}: …
- {vertical-specific 2}: …
(Caveat: this is a sample, not a comprehensive citation audit. For definitive coverage, use Whitespark / BrightLocal / Yext.)
## Schema status
- LocalBusiness JSON-LD: {present and valid / present but missing recommended properties / invalid / absent}
- Recommended next step: run `seo-schema {homepage_url}` for paste-ready LocalBusiness markup with the correct industry subtype.
## Limitations
This skill could NOT assess:
- **Geo-grid local-pack rank by lat/long.** Requires a Maps API (e.g. DataForSEO Maps geo-grid endpoint) we don't have. Workaround: pay for Local Falcon, GMB Crush, or BrightLocal Local Search Grid.
- **Comprehensive citation audit.** WebSearch sampling covers ~8 directories; full audits cover 50+. Use Whitespark, BrightLocal, or Yext.
- **GBP Insights data.** Requires GBP API access scoped to the listing owner. Ask the listing owner to export Insights and share.
- **Real-time local-pack rank tracking over time.** This skill is a snapshot. Use SE Ranking's project-level rank tracker (`PROJECT_runPositionCheck`) or pair with `seo-drift` for diff snapshots.
- **DataForSEO Business Listings.** Not in our backend; if the user needs it, they'd need to subscribe to DataForSEO directly.local-keywords.csv columns: keyword,country,location,local_pack_present,target_in_pack,target_pack_position,target_organic_position,top_pack_competitor_1,top_pack_competitor_2,top_pack_competitor_3,aio_present
nap-inconsistencies.csv columns: source,name,address,phone,page_or_schema_path,canonical_value,divergence_note
DATA_getSerpResults calls sequentially.DATA_getCreditBalance before running. ~15–25 SE Ranking credits typical, plus 6–12 Firecrawl credits when Firecrawl is installed.seo-schema for that — it has the rich-results validation and industry-subtype routing this skill doesn't replicate.seo-content-audit on a sample of location pages.seo-geo (URL-level GEO) or seo-ai-search-share-of-voice (domain-level brand visibility) for AI-search local visibility.references/local-citation-sources.md. The list is curated to the directories that move the needle (Tier 1 + vertical-specific), not the long tail.seo-technical-audit if site-wide technical-SEO issues surface in step 8 — this skill scopes to local-relevant findings, not the full audit.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.