Skip to main content
skill CX Codex

schema-markup · openclaudia — Claude Code skill: JSON-LD for any page type

This skill writes Schema.org JSON-LD for the page type you have: article, product, FAQ, how-to. Useful when you want rich results in search.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add OpenClaudia/openclaudia-skills --skill schema-markup -a claude-code
Open on GitHub

What schema-markup does

The skill picks the right schema type from the page content and returns ready JSON-LD. It ships templates for Article, BlogPosting, NewsArticle, Product, FAQPage and HowTo, each with Google's rich result requirements attached.

Article needs headline under 110 characters, image in three aspect ratios (16:9, 4:3, 1:1, each wider than 696px), datePublished in ISO 8601 and an author name. Product needs at least one of offers, review or aggregateRating, and price plus currency once offers is there. Google only shows FAQPage markup when the questions are visible on the page rather than hidden behind tabs, so check your markup before pasting the code in.

Install runs through npx skills add for Claude, Codex, Cursor, Gemini CLI and OpenCode. GitHub Copilot uses gh skill install instead. The skill file lands at a path like .cursor/skills/schema-markup/SKILL.md or ~/.claude/skills/schema-markup/SKILL.md, so you can edit the templates for your own project.

What it helps with

  • generate JSON-LD for a product page with price and availability
  • mark up an FAQ block so it can appear as a rich result
  • add article markup with author, date and images
  • describe a step-by-step guide with HowTo
  • check required schema fields before publishing

Example prompts for the agent

  • generate schema markup for this product page
  • I need JSON-LD for the FAQ on this page
  • add Article markup to my blog post

How to install schema-markup

1Skills CLI (Vercel)

npx skills add OpenClaudia/openclaudia-skills --skill schema-markup -a claude-code

2Manually: put the files in place

~/.claude/skills/schema-markup/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/schema-markup/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about schema-markup

How do I install schema-markup in Claude?

Run npx skills add OpenClaudia/openclaudia-skills --skill schema-markup -a claude-code. The file lands at ~/.claude/skills/schema-markup/SKILL.md.

What does schema-markup do?

It generates Schema.org JSON-LD for the page type you pick: article, product, FAQ or how-to. Google's rich result requirements are built into each template.

Which page types does the skill cover?

Article, BlogPosting, NewsArticle, Product, FAQPage and HowTo. The type is chosen from the page content.

Source text

SKILL.md · MIT
---
name: schema-markup
description: Generate Schema.org structured data (JSON-LD) for any page type. Use when the user says "schema markup", "structured data", "JSON-LD", "rich snippets", "rich results", "FAQ schema", "product schema", "article schema", "breadcrumb schema", "organization schema", "how-to schema", "review schema", or asks about structured data for SEO.
---

# Schema Markup Generator Skill

You are an expert in Schema.org structured data and Google's rich results requirements. Generate valid, complete JSON-LD markup that maximizes eligibility for Google rich results.

## Supported Schema Types

This skill supports the following schema types. When the user asks for schema, determine which type(s) are appropriate based on the page content.

### 1. Article / BlogPosting / NewsArticle

**Use for:** Blog posts, news articles, editorial content
**Rich result:** Article carousel, headline in search

```json
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Your Article Title (max 110 characters)",
  "description": "Brief description of the article (max 160 characters)",
  "image": [
    "https://example.com/image-16x9.jpg",
    "https://example.com/image-4x3.jpg",
    "https://example.com/image-1x1.jpg"
  ],
  "datePublished": "2025-01-15T08:00:00+00:00",
  "dateModified": "2025-01-20T10:30:00+00:00",
  "author": [{
    "@type": "Person",
    "name": "Author Name",
    "url": "https://example.com/author/name",
    "jobTitle": "Senior Editor",
    "sameAs": [
      "https://twitter.com/authorhandle",
      "https://linkedin.com/in/authorname"
    ]
  }],
  "publisher": {
    "@type": "Organization",
    "name": "Publisher Name",
    "logo": {
      "@type": "ImageObject",
      "url": "https://example.com/logo.png",
      "width": 600,
      "height": 60
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://example.com/article-url"
  },
  "wordCount": 2500,
  "articleSection": "Technology",
  "keywords": ["keyword1", "keyword2", "keyword3"],
  "isAccessibleForFree": true
}
```

**Google requirements:**
- `headline` is required (max 110 characters)
- `image` is required (provide 3 aspect ratios: 16:9, 4:3, 1:1; each > 696px wide)
- `datePublished` is required (ISO 8601 format)
- `author.name` is required
- For `NewsArticle`, also add `dateline` if applicable
- For `BlogPosting`, `@type` changes to `"BlogPosting"`

---

### 2. Product

**Use for:** Product pages, e-commerce listings
**Rich result:** Product snippet with price, availability, reviews

```json
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Product Name",
  "description": "Product description",
  "image": [
    "https://example.com/product-1.jpg",
    "https://example.com/product-2.jpg"
  ],
  "sku": "SKU-12345",
  "mpn": "MPN-67890",
  "gtin13": "0123456789012",
  "brand": {
    "@type": "Brand",
    "name": "Brand Name"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/product",
    "priceCurrency": "USD",
    "price": "99.99",
    "priceValidUntil": "2025-12-31",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition",
    "seller": {
      "@type": "Organization",
      "name": "Seller Name"
    },
    "shippingDetails": {
      "@type": "OfferShippingDetails",
      "shippingRate": {
        "@type": "MonetaryAmount",
        "value": "0",
        "currency": "USD"
      },
      "deliveryTime": {
        "@type": "ShippingDeliveryTime",
        "handlingTime": {
          "@type": "QuantitativeValue",
          "minValue": 0,
          "maxValue": 1,
          "unitCode": "DAY"
        },
        "transitTime": {
          "@type": "QuantitativeValue",
          "minValue": 1,
          "maxValue": 5,
          "unitCode": "DAY"
        }
      },
      "shippingDestination": {
        "@type": "DefinedRegion",
        "addressCountry": "US"
      }
    },
    "hasMerchantReturnPolicy": {
      "@type": "MerchantReturnPolicy",
      "applicableCountry": "US",
      "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
      "merchantReturnDays": 30,
      "returnMethod": "https://schema.org/ReturnByMail",
      "returnFees": "https://schema.org/FreeReturn"
    }
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "bestRating": "5",
    "ratingCount": "142"
  },
  "review": [{
    "@type": "Review",
    "author": {
      "@type": "Person",
      "name": "Reviewer Name"
    },
    "datePublished": "2025-01-10",
    "reviewBody": "Review text here",
    "reviewRating": {
      "@type": "Rating",
      "ratingValue": "5",
      "bestRating": "5"
    }
  }]
}
```

**Google requirements:**
- `name` is required
- `offers`, `review`, or `aggregateRating` - at least one required
- `offers.price` and `offers.priceCurrency` required if offers present
- `offers.availability` must use Schema.org enum values
- As of 2024, `shippingDetails` and `hasMerchantReturnPolicy` are recommended for merchant listings

---

### 3. FAQPage

**Use for:** FAQ sections, Q&A pages
**Rich result:** Expandable FAQ in search results

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is the first question?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "<p>The answer with <strong>HTML formatting</strong> allowed. You can include <a href=\"https://example.com\">links</a>.</p>"
      }
    },
    {
      "@type": "Question",
      "name": "What is the second question?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Plain text answers also work."
      }
    }
  ]
}
```

**Google requirements:**
- Each `Question` must have exactly one `acceptedAnswer`
- Answer `text` can include HTML: `<h2>` through `<h6>`, `<br>`, `<ol>`, `<ul>`, `<li>`, `<a>`, `<p>`, `<b>`, `<strong>`, `<i>`, `<em>`
- Must be visible on the page (not hidden behind tabs/accordions without proper implementation)
- Google may show up to 3 FAQ rich results per page
- Do not use for advertising purposes

---

### 4. HowTo

**Use for:** Tutorial pages, step-by-step guides, DIY instructions
**Rich result:** Step-by-step display in search results

```json
{
  "@context": "https://schema.org",
  "@type": "HowTo",
  "name": "How to Do Something",
  "description": "Brief description of the task",
  "image": {
    "@type": "ImageObject",
    "url": "https://example.com/howto-main.jpg",
    "height": "406",
    "width": "305"
  },
  "totalTime": "PT30M",
  "estimatedCost": {
    "@type": "MonetaryAmount",
    "currency": "USD",
    "value": "20"
  },
  "supply": [
    {
      "@type": "HowToSupply",
      "name": "Supply item 1"
    },
    {
      "@type": "HowToSupply",
      "name": "Supply item 2"
    }
  ],
  "tool": [
    {
      "@type": "HowToTool",
      "name": "Tool 1"
    }
  ],
  "step": [
    {
      "@type": "HowToStep",
      "name": "Step 1 Title",
      "text": "Detailed instructions for step 1.",
      "url": "https://example.com/howto#step1",
      "image": "https://example.com/step1.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Step 2 Title",
      "text": "Detailed instructions for step 2.",
      "url": "https://example.com/howto#step2",
      "image": "https://example.com/step2.jpg"
    }
  ]
}
```

**Google requirements:**
- `name` is required
- `step` array is required with at least one step
- Each step needs either `text` or `itemListElement` with `HowToDirection`/`HowToTip`
- `totalTime` uses ISO 8601 duration format (PT1H30M = 1 hour 30 minutes)
- Do not use HowTo for recipes (use Recipe schema instead)

---

### 5. Organization

**Use for:** Homepage, about page, company information
**Rich result:** Knowledge panel, logo in search

```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Company Name",
  "alternateName": "Company Abbreviation",
  "url": "https://example.com",
  "logo": {
    "@type": "ImageObject",
    "url": "https://example.com/logo.png",
    "width": 512,
    "height": 512
  },
  "description": "Company description",
  "foundingDate": "2020-01-01",
  "founder": {
    "@type": "Person",
    "name": "Founder Name"
  },
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "San Francisco",
    "addressRegion": "CA",
    "postalCode": "94102",
    "addressCountry": "US"
  },
  "contactPoint": [{
    "@type": "ContactPoint",
    "telephone": "+1-555-555-5555",
    "contactType": "customer service",
    "areaServed": "US",
    "availableLanguage": "English"
  }],
  "sameAs": [
    "https://twitter.com/company",
    "https://linkedin.com/company/company",
    "https://facebook.com/company",
    "https://github.com/company"
  ],
  "numberOfEmployees": {
    "@type": "QuantitativeValue",
    "minValue": 10,
    "maxValue": 50
  }
}
```

---

### 6. LocalBusiness

**Use for:** Local business pages, Google Business Profile support
**Rich result:** Local business panel, map results

```json
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://example.com/#business",
  "name": "Business Name",
  "description": "Business description",
  "url": "https://example.com",
  "telephone": "+1-555-555-5555",
  "email": "[email protected]",
  "image": "https://example.com/storefront.jpg",
  "logo": "https://example.com/logo.png",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "San Francisco",
    "addressRegion": "CA",
    "postalCode": "94102",
    "addressCountry": "US"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": "37.7749",
    "longitude": "-122.4194"
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "09:00",
      "closes": "17:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday",
      "opens": "10:00",
      "closes": "14:00"
    }
  ],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "bestRating": "5",
    "ratingCount": "312"
  },
  "areaServed": {
    "@type": "City",
    "name": "San Francisco"
  },
  "hasMap": "https://maps.google.com/?cid=123456789"
}
```

**Google requirements:**
- `name`, `address` are required
- Use specific subtypes when possible: `Restaurant`, `Dentist`, `LegalService`, `RealEstateAgent`, etc.
- `geo` coordinates should be accurate to the business location
- `openingHoursSpecification` must reflect actual business hours

---

### 7. BreadcrumbList

**Use for:** Any page with breadcrumb navigation
**Rich result:** Breadcrumb trail in search results

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://example.com"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Category",
      "item": "https://example.com/category"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Current Page Title"
    }
  ]
}
```

**Google requirements:**
- `position` must be sequential starting at 1
- Last item should not have `item` (it's the current page)
- Must match the visible breadcrumb on the page

---

### 8. Review / AggregateRating

**Use for:** Review pages, product reviews, service reviews
**Rich result:** Star rating in search results

```json
{
  "@context": "https://schema.org",
  "@type": "Review",
  "name": "Review Title",
  "reviewBody": "Full review text...",
  "datePublished": "2025-01-15",
  "author": {
    "@type": "Person",
    "name": "Reviewer Name"
  },
  "itemReviewed": {
    "@type": "Product",
    "name": "Product Being Reviewed",
    "image": "https://example.com/product.jpg"
  },
  "reviewRating": {
    "@type": "Rating",
    "ratingValue": "4",
    "bestRating": "5",
    "worstRating": "1"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Review Site Name"
  }
}
```

**Google requirements:**
- `author` is required (must be a valid `Person` or `Organization`)
- `itemReviewed` is required
- `reviewRating` is recommended
- Self-serving reviews (reviewing your own product) are against guidelines

## Multi-Schema Pages

Most pages need multiple schema types. Combine them using `@graph`:

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Company Name",
      "url": "https://example.com",
      "logo": "https://example.com/logo.png"
    },
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "url": "https://example.com",
      "name": "Site Name",
      "publisher": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "WebPage",
      "@id": "https://example.com/page/#webpage",
      "url": "https://example.com/page/",
      "name": "Page Title",
      "isPartOf": { "@id": "https://example.com/#website" }
    },
    {
      "@type": "Article",
      "mainEntityOfPage": { "@id": "https://example.com/page/#webpage" },
      "headline": "Article Title",
      "author": { "@type": "Person", "name": "Author" },
      "publisher": { "@id": "https://example.com/#organization" },
      "datePublished": "2025-01-15"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com" },
        { "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://example.com/blog" },
        { "@type": "ListItem", "position": 3, "name": "Article Title" }
      ]
    }
  ]
}
```

## Generation Process

When the user asks for schema markup:

1. **Determine page type** - Ask what kind of page this is for (or infer from context)
2. **Gather information** - Ask for or collect the required fields. If the user provides a URL, fetch it to extract data.
3. **Select schema types** - Choose all applicable schemas (most pages need 2-4 types)
4. **Generate JSON-LD** - Create complete, valid markup
5. **Validate** - Check against Google's requirements for each type
6. **Provide implementation instructions** - Tell the user exactly where to place it

## Implementation Instructions

For **Next.js App Router**:
```tsx
// In your page component or layout
export default function Page() {
  const jsonLd = {/* generated schema */};

  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      {/* page content */}
    </>
  );
}
```

For **Next.js with next/head (Pages Router)**:
```tsx
import Head from 'next/head';

export default function Page() {
  const jsonLd = {/* generated schema */};

  return (
    <>
      <Head>
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        />
      </Head>
      {/* page content */}
    </>
  );
}
```

For **plain HTML**:
```html
<head>
  <script type="application/ld+json">
  {/* generated schema */}
  </script>
</head>
```

## Validation

After generating the markup, remind the user to validate using:
1. **Google Rich Results Test:** https://search.google.com/test/rich-results
2. **Schema.org Validator:** https://validator.schema.org/

## Common Mistakes to Avoid

- Do not add schema for content that is not visible on the page
- Do not use `Review` schema for self-serving reviews of your own business
- Do not markup content behind a paywall as `isAccessibleForFree: true`
- Do not use fake or placeholder data in production schema
- Do not add `AggregateRating` without actual user reviews
- Always use absolute URLs, never relative
- Always use ISO 8601 date format
- `priceValidUntil` must be a future date
- `availability` must use full Schema.org URL (e.g., `https://schema.org/InStock`)
- Image URLs must be crawlable and indexable

© OpenClaudia · MIT · OpenClaudia/openclaudia-skills

Similar skills

Everything for SEO and GEO →

schema-markup by other authors comes first.

schema-markup Alireza Rezvani A Claude skill for implementing, auditing and fixing schema.org markup. Useful when rich snippets never show up or Search Console flags structured data errors. 617installs schema-markup kostja94 Generates Schema.org JSON-LD structured data for rich snippets and AI search engines. Helps match page content to supported search engine formats. CX Codex +1 1,300installs schema coreyhaines31 This skill helps add or repair structured data on site pages. Use it to draft JSON-LD and check whether Google currently supports the rich result you want. CX Codex +1 78,300installs blog-schema AgriciDaniel Generates a single JSON-LD graph for a blog post, linking the author and organization. Useful when preparing structured data for articles. CX Codex +1 2,500installs serp-markup-builder aaron-he-zhu Builds the document head: title and description options, an Open Graph and Twitter Card block, and validated JSON-LD for rich results. CX Codex +1 1,400installs geo-schema geo-seo-claude Audits JSON-LD, Microdata, and RDFa structured data on web pages, checks validation rules, and generates clean markup for search and AI discovery. CX Codex +1 915installs seo-local-business jezweb Generates a complete local SEO package: <head> meta tags, JSON-LD LocalBusiness schema, robots.txt, and sitemap.xml for service-based websites. CX Codex +1 1,800installs seo affaan-m A skill that walks your coding agent through technical SEO, on-page fixes, structured data and Core Web Vitals, with page-level recommendations. CX Codex +1 5,100installs

From the same set61

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor