/schema-markup — JSON-LD generation + validation
Generate validated JSON-LD schema markup for a page (or batch of pages) based on the page type, available data, and target rich results. Output is paste-ready code plus a validation checklist.
This is a page-level execution skill, not a strategic SEO planning skill. Decide what content to produce via /aeo-strategy or /content-strategy first; this skill structures the markup once the content exists.
Doctrine inherited (Step 7 — 0626 rollout, locked 2026-06-04)
Output complies with output-tenets.md, output-simplicity.md, Step 6 calibration: see [[feedback_execution_doctrine_refinements_step6]].
Refinements applied to this skill (internal-reference floor):
| Code | Refinement | How it lands in schema-markup |
|---|---|---|
| R1 | Source placement | JSON-LD output is structured data, not narrative — internal-reference. Schema property attribution stays inline. |
| R3 | Product-update tone | Skill-summary reports (validation pass/fail) frame as operator-direct. |
| R9 | Action-oriented section names | "Generate / Validate / Paste" — verb-led. |
Note: internal-reference skill; R2/R5/R6/R7/R8 do not apply.
When to invoke
- A page is shipping (new or refresh) and needs structured data before publish.
- An audit found pages missing schema or with invalid markup.
- A client is getting cited by AI engines (Perplexity, ChatGPT, Claude) but lacks validated schema to lock in eligibility.
- A
/aeo-contentrun is complete and you want the schema layer applied alongside.
Do NOT invoke when:
- The page content doesn't exist yet (write copy first via
/aeo-contentor/landing-page-copy). - The audit is broader than schema (
/website-auditcovers crawlability, Core Web Vitals, on-page).
Workflow
Step 1 — Page-type assessment
Identify the page's content type. Match to schema.org type + eligible rich result:
| Page type | Schema type | Eligible rich result |
|---|---|---|
| Product detail (SaaS or physical) | Product (+ Offer, AggregateRating) |
Product snippet, price, review stars |
| Pricing page | Product (one per tier) or Offer list |
Price + availability |
| Blog post / article | Article or BlogPosting |
Article rich result (image, date, byline) |
| Long-form guide | Article + HowTo (if step-by-step) |
Article + HowTo rich result |
| FAQ page or FAQ section | FAQPage |
FAQ rich result |
| Company about | Organization |
Knowledge panel, logo |
| Founder / author bio | Person |
Knowledge panel for the person |
| Event landing page | Event |
Event rich result (date, location) |
| Case study | Article + Review (if customer testimonial-anchored) |
Article rich result; review stars |
| Local-service page | LocalBusiness (+ Service) |
Local pack eligibility, hours |
| Software comparison page | SoftwareApplication + Review per option |
Software rich result + review stars |
| Job posting | JobPosting |
Job rich result on Google for Jobs |
| Breadcrumb (every page) | BreadcrumbList |
Breadcrumb rich result |
Step 2 — Required properties check
Each schema type has required properties Google enforces. Cross-check before generation:
Organization→name,url. Recommended:logo,sameAs(social URLs).Article→headline,image,datePublished,author(Person or Organization).Product→name,image,offers(withprice,priceCurrency). Recommended:aggregateRating,review.FAQPage→mainEntityarray ofQuestionobjects, each withacceptedAnswer.Event→name,startDate,location. Recommended:offers,performer.HowTo→name,steparray (each step withname+text).Review→itemReviewed,reviewRating,author.
Pull values from existing page content. If a required value is missing from the page, do not invent it — flag as a content gap to fix before adding schema.
Step 3 — @graph composition for multi-type pages
When a page has multiple eligible schema types (e.g., article + author + organization + breadcrumb), wrap in a single @graph rather than emitting four separate <script> blocks. One @type: ItemList parent with referenced child entities reduces collisions and is Google's recommended pattern.
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "Organization", "@id": "https://example.com/#org", "name": "...", "url": "..." },
{ "@type": "Person", "@id": "https://example.com/#author", "name": "..." },
{ "@type": "Article", "@id": "https://example.com/post/#article", "headline": "...", "author": { "@id": "https://example.com/#author" } },
{ "@type": "BreadcrumbList", "itemListElement": [...] }
]
}
Step 4 — Generate JSON-LD
Output the complete <script type="application/ld+json"> block ready to paste into the page's <head> (preferred) or end of <body>. Always JSON-LD format (Google's recommended approach); never microdata or RDFa.
Step 5 — Validate
Provide the validation checklist:
- Paste the URL into Google's Rich Results Test — confirm zero errors and the expected rich-result types detected.
- Verify the markup represents actual visible page content. Schema-content mismatch is Google's #1 manual-action trigger.
- Confirm Search Console "Enhancements" report picks up the new markup within 7–14 days of publish.
- For JavaScript-injected schema, confirm via Rich Results Test (Google fetches it) —
web_fetchand similar tools cannot detect JS-injected markup.
Sharp rules + anti-patterns
- ✅ JSON-LD only. Never microdata or RDFa for new work.
- ✅ Schema reflects visible content. If it's in schema, it must be on the page.
- ✅ One
@graphper page, not multiple<script>blocks. - ✅ Required properties present per type before publish.
- ❌ Hidden content in schema only ("invisible" reviews, prices not shown on the page). Manual-action territory.
- ❌ Wishful properties (
aggregateRatingwith 1 review and rating 5.0). Google may treat as spam. - ❌ Inventing
sameAsURLs to social profiles that don't exist. Validation catches it. - ❌ Schema for navigational pages that don't have rich-result eligibility — wastes review effort.
Page: {url or path}
Page type assessment
- Detected: {ArticleType / Product / FAQ / etc.}
- Eligible rich results: {list}
Required properties — fill / gap check
- ✅ {property}: {value pulled from page}
- ⚠️ {property}: {GAP — value missing from page, flag to content owner}
Generated JSON-LD
```html
```
Validation checklist
- Paste URL into Rich Results Test — zero errors
- Detected rich-result types match expectations
- No schema-content mismatch (manual eyeball check)
- Search Console Enhancements report updated within 14 days
---
## Integration with other skills
- **Upstream:** `/aeo-content` produces the page content; this skill structures it. `/website-audit` may flag missing schema and route here.
- **Downstream:** `/aeo-strategy` consumes the citation lift; `/website-audit` re-checks via the validation step.
- **Companion:** `/aeo-content` (write the page) → `/schema-markup` (structure it) → publish.
---
## Attribution
This skill adapts patterns from [`coreyhaines31/marketingskills/schema/SKILL.md`](https://github.com/coreyhaines31/marketingskills/blob/main/skills/schema/SKILL.md) (MIT license, © Corey Haines / Conversion Factory). Adapted to Genesys operator voice and integrated with our existing AEO chain.
---
## Final ship gate
Run `/premortem --output` before ship. See [`/premortem` skill](../../../../meta/orchestration/premortem/SKILL.md) for the 5 execution domains (will-it-resonate / will-it-convert / will-it-stay-on-brand / will-stakeholder-push-back / will-it-degrade-over-time) and output template.
Trivial-case escape: `## Premortem\nNo failure modes — trivial change` satisfies the contract for genuinely trivial outputs.
---