SEO Schema Audit

Structured data only works when it describes what a visitor can actually see. Google's policy is explicit: schema must reflect content visible in the served HTML. Most schema failures come from violating this in ways that look fine in the React tree.

Render through growth-report-format. Open it alongside this skill.

Tools this skill calls

Need Tool Key arguments
Declared schema types + FAQ schema-vs-visible comparison mcp__google_search_mcp__audit_page urls (1–20), response_format: "json"
Whether Google has indexed the page and what it saw mcp__google_search_mcp__gsc_url_inspect site_url, inspection_url

Default property for Agentman work: GSC sc-domain:agentman.ai. Any other site: resolve the target first.

audit_page is the fastest path to failure mode 1. It returns:

  • schemaTypes — every distinct @type on the page, @graph flattened
  • faq{schemaCount, visibleCount, missingFromPage} when FAQPage schema exists, null when it does not
  • __INVALID_JSON__ inside schemaTypes when a ld+json block failed to parse (search engines ignore those entirely)

visibleCount below schemaCount is the violation. missingFromPage names the exact questions.

Provenance rules

  1. Every finding names the call that produced it.
  2. audit_page returns no performance data — no CTR, impressions, or position. Do not attach performance claims to schema findings.
  3. A failed or empty call is reported, never filled in from memory.
  4. Never cite a prior audit that is not in the current context.

What audit_page cannot settle

  • It reads server-rendered HTML only — which is the right lens for this skill, since that is what Google parses.
  • It does not resolve ancestor visibility: a question inside a hidden container can read as visible. So visibleCount == schemaCount means "nothing obviously wrong", not proof. When the stakes are high (a page you are about to submit for rich results), confirm by eye.
  • It does not validate Offer correctness, breadcrumb ordering, or required-property completeness. Those are manual checks below.

The three failure modes to hunt for

1. Schema describing invisible content

Run audit_page on the URL set. Any page where faq.visibleCount < faq.schemaCount is failing this test, and faq.missingFromPage lists the questions Google cannot see.

The classic trap: accordion components unmount collapsed panels. Radix UI, Headless UI, and most disclosure components remove closed content from the DOM entirely — so a FAQ page emits FAQPage schema for answers that are not in the HTML. Fix by force-mounting the content and hiding it with CSS instead (Radix: forceMount on AccordionContent plus data-[state=closed]:hidden). Make this an opt-in prop on the shared accordion so other usages keep their animations.

For non-FAQ schema types, audit_page reports which types are present but does not verify each claim. Fetch the page and confirm every referenced string exists in the same document.

2. Fabricated offers

Every Offer must state a real, current price:

  • Never emit "price": "0" or invent a "free trial" because a template defaulted that way. If the product costs money, a $0 offer is a misrepresentation Google can act on.
  • If pricing is per-unit or usage-based, use the real entry price with priceCurrency and describe the unit.
  • If a product is only sold as part of a suite with no standalone price, omit the Offer entirely rather than fabricate one.
  • Pull every price from the site's single pricing module — the same import the visible pricing UI uses — so schema can never drift from displayed prices.

3. Hand-written schema drifting from copy

Never maintain schema as a separate literal. Export the content array (FAQ items, feature lists, prices) from the component that renders it, and build the JSON-LD from that same array. One source; drift becomes impossible.

Schema selection by page type

  • Product / agent / feature page: SoftwareApplication or Product (+ real Offer if priced standalone)
  • Pricing page: Product with Offer per tier from the pricing module
  • Pages with a visible FAQ: FAQPage from the exported FAQ array
  • Any page below the homepage: BreadcrumbList matching the visible breadcrumb/nav path
  • Directory detail pages: BreadcrumbList + FAQPage where a real FAQ renders

Verification

  1. audit_page across the affected URLs — confirm schemaTypes holds what you expect, no __INVALID_JSON__, and faq.visibleCount == faq.schemaCount.
  2. Fetch the page for claims outside the FAQ block and confirm each referenced string is in the served document.
  3. Run the URL through Google's Rich Results Test.
  4. gsc_url_inspect to confirm Google has actually indexed the current version.
  5. Re-check after any component library upgrade — unmount behavior is exactly the kind of thing a minor version changes silently.

Output — the Findings section

Per page: URL, schema types present, FAQ counts, the specific violation, and the fix. Use the structural-findings table from growth-report-format (Page | Issue | Severity | Fix). Severity: a FAQ visibility violation or invalid JSON-LD is High; a missing optional property is Low.

Worked example

Input: a review found eight product pages emitting Offer schema with "price": "0" and a "free trial" that didn't exist — the real product billed $25 per submission. Separately, three pages emitted FAQPage schema whose answers were absent from the served HTML: the accordion library unmounted every closed panel, so only the questions existed in the document.

Output:

  • Offers rebuilt from the shared pricing module: "price": "25.00", "priceCurrency": "USD", unit described in the offer name. Suite-priced products with no standalone price lost their Offer entirely rather than getting an invented one.
  • The shared accordion component gained an opt-in alwaysRenderContent prop (forceMount + data-[state=closed]:hidden), so FAQ answers exist in the HTML while collapsed — and every other accordion on the site kept its original unmount behavior and animations.
  • Each page's FAQPage JSON-LD was rebuilt from the same exported array the accordion renders, eliminating the drift that caused the mismatch in the first place.

Today that first diagnosis is one audit_page call: the three bad pages would have returned faq.visibleCount of 0 against a schemaCount of 5, with every question listed in missingFromPage.

SEO Schema Audit

By Agentman

Audit and implement Google structured data (JSON-LD) correctly: FAQPage, Product/Offer, SoftwareApplication, BreadcrumbList. Catches the failures that get rich results ignored or penalized — schema de

Marketingv1.3.0
seostructured-dataschemajson-ldrich-resultsschema-markup-validatormcp-bound

Ready to use this skill?

Attach it to your Agentman agents, or clone it and make it yours.

Free to use. Clone this and any other public skill with a free Agentman account — publishing your own is free up to 10 skills.

AgentSkills is more than a copy-paste library

  • Versioned, not pastedEdit a skill once and every agent using it follows the new version.
  • Shared with your teamOne library with per-skill access control and a record of who did what.
  • One connectionA single MCP link works across Claude, ChatGPT, Cursor and Agentman agents.
Explore AgentSkills →

Or try it in an assistant