---
name: geo-fix-schema
description: Analyze a website's structured data and generate ready-to-use JSON-LD schema markup to improve AI discoverability. Use when the user asks to fix schema, add structured data, generate JSON-LD, add schema markup, or improve schema.org markup for AI engines.
version: 1.0.0
---

# geo-fix-schema Skill

You analyze a website's existing structured data and generate ready-to-use JSON-LD schema markup that improves AI discoverability and citation likelihood. The output is copy-paste-ready code that the user can inject into their site's `<head>`.

Refer to `references/schema-templates.md` in this skill's directory for JSON-LD template patterns.

---

## Phase 1: Discovery

### 1.1 Validate Input

Extract the target URL from the user's input. Normalize it:
- Add `https://` if no protocol specified
- Remove trailing slashes
- Extract the base domain

### 1.2 Fetch and Analyze Pages

Fetch the homepage and up to 5 additional key pages (about, blog post, product page, FAQ, contact).

For each page, extract:
- All `<script type="application/ld+json">` blocks
- Microdata attributes (`itemscope`, `itemtype`, `itemprop`)
- RDFa attributes (`typeof`, `property`)
- `<meta>` tags (og:*, twitter:*, description, author)
- Page content structure (headings, lists, Q&A patterns)

### 1.3 Detect Business Type

Classify the site based on content signals:

| Type | Signals |
|------|---------|
| **SaaS** | Sign up, pricing, API, dashboard, integrations |
| **E-commerce** | Cart, buy, product listings, prices, SKUs |
| **Publisher** | Articles, bylines, dates, categories |
| **Local Business** | Address, phone, hours, map, service area |
| **Agency** | Services, case studies, portfolio, client logos |

---

## Phase 2: Schema Audit

### 2.1 Inventory Existing Schema

Build a table of what exists:

```
Schema Audit: {domain}

| Schema Type | Found | Format | Valid | Issues |
|-------------|-------|--------|-------|--------|
| Organization | Yes/No | JSON-LD/Microdata/None | Yes/No | ... |
| WebSite | Yes/No | ... | ... | ... |
| Article | Yes/No | ... | ... | ... |
| ...
```

### 2.2 Score Current State

Use the scoring rubric from the geo-audit schema dimension:

| Check | Max Points | Current |
|-------|-----------|---------|
| Core Identity Schema | 30 | {x}/30 |
| Content Schema | 25 | {x}/25 |
| AI-Boost Schema | 25 | {x}/25 |
| Schema Quality | 20 | {x}/20 |
| **Total** | **100** | **{x}/100** |

### 2.3 Identify Gaps

For each missing or incomplete schema, document:
- What's missing
- Why it matters for AI visibility
- Point impact (how much the score would improve)
- Priority (Critical / High / Medium / Low)

---

## Phase 3: Generate JSON-LD

Generate ready-to-use JSON-LD for each gap, ordered by priority.

### 3.1 Core Identity (always generate if missing)

**Organization / LocalBusiness:**

Extract from the site:
- Name (from title, og:site_name, footer, about page)
- Description (from meta description, about page)
- Logo URL (from og:image, header logo, favicon)
- URL (canonical domain)
- Social profiles (from footer links, og:see_also)
- Contact info (from contact page, footer)

Generate:
```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "{extracted name}",
  "url": "{url}",
  "logo": "{logo_url}",
  "description": "{extracted description}",
  "sameAs": [
    "{linkedin_url}",
    "{twitter_url}",
    "{github_url}"
  ],
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer service",
    "url": "{contact_page_url}"
  }
}
```

For Local Business, use `@type: "LocalBusiness"` and add:
- `address` (PostalAddress)
- `telephone`
- `openingHoursSpecification`
- `geo` (latitude, longitude)

**WebSite + SearchAction:**

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "{site_name}",
  "url": "{url}",
  "potentialAction": {
    "@type": "SearchAction",
    "target": "{url}/search?q={search_term_string}",
    "query-input": "required name=search_term_string"
  }
}
```

Only include SearchAction if a search function exists on the site.

### 3.2 Content Schema (generate per content page)

**Article / BlogPosting:**

Extract from each article page:
- Headline (H1)
- Author (byline, author meta)
- Date published / modified
- Description (meta description or first paragraph)
- Image (og:image or first content image)
- Word count

```json
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "{h1}",
  "author": {
    "@type": "Person",
    "name": "{author_name}",
    "url": "{author_url}"
  },
  "datePublished": "{iso_date}",
  "dateModified": "{iso_date}",
  "description": "{meta_description}",
  "image": "{image_url}",
  "publisher": {
    "@type": "Organization",
    "name": "{site_name}",
    "logo": {
      "@type": "ImageObject",
      "url": "{logo_url}"
    }
  },
  "mainEntityOfPage": "{canonical_url}",
  "wordCount": {word_count},
  "speakable": {
    "@type": "SpeakableSpecification",
    "cssSelector": ["h1", ".article-summary", ".article-body p:first-of-type"]
  }
}
```

**Person (Author):**

If author pages exist, generate Person schema with:
- name, url, jobTitle, worksFor, sameAs (social links)

### 3.3 AI-Boost Schema (generate when content patterns match)

**FAQPage:**

Detect Q&A patterns in page content:
- `<h2>` or `<h3>` phrased as questions
- Sections with "Q:" / "A:" patterns
- Accordion/expandable FAQ elements

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "{question_text}",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "{answer_text}"
      }
    }
  ]
}
```

**HowTo:**

Detect step-by-step content:
- Numbered lists
- "Step 1", "Step 2" headings
- Tutorial/guide content

```json
{
  "@context": "https://schema.org",
  "@type": "HowTo",
  "name": "{title}",
  "description": "{description}",
  "step": [
    {
      "@type": "HowToStep",
      "name": "{step_title}",
      "text": "{step_description}"
    }
  ]
}
```

**BreadcrumbList:**

Generate from URL structure and navigation:

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "{url}"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "{section}",
      "item": "{section_url}"
    }
  ]
}
```

**Product (E-commerce only):**

```json
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "{product_name}",
  "description": "{description}",
  "image": "{image_url}",
  "brand": {
    "@type": "Brand",
    "name": "{brand}"
  },
  "offers": {
    "@type": "Offer",
    "price": "{price}",
    "priceCurrency": "{currency}",
    "availability": "https://schema.org/InStock",
    "url": "{product_url}"
  }
}
```

---

## Phase 4: Output

### 4.1 Generate Installation File

Create a file named `schema-{domain}.json` containing all generated JSON-LD blocks, each wrapped in a `<script>` tag and annotated with comments indicating which page it belongs to:

```html
<!-- ============================================ -->
<!-- HOMEPAGE: Organization + WebSite             -->
<!-- Place in <head> of: {url}                    -->
<!-- ============================================ -->
<script type="application/ld+json">
{...Organization JSON-LD...}
</script>

<script type="application/ld+json">
{...WebSite JSON-LD...}
</script>

<!-- ============================================ -->
<!-- BLOG POST: Article                           -->
<!-- Place in <head> of: {blog_post_url}          -->
<!-- ============================================ -->
<script type="application/ld+json">
{...Article JSON-LD...}
</script>
```

### 4.2 Print Summary

```
Schema Fix: {domain}

Current score: {x}/100
After fixes:   {y}/100 (estimated +{delta} points)

Generated {n} JSON-LD blocks:

| Schema | Page | Impact | Why It Matters |
|--------|------|--------|----------------|
| Organization | Homepage | +12 pts | AI uses this to identify your brand and link to knowledge graphs |
| WebSite | Homepage | +5 pts | Enables sitelinks search box in AI-generated answers |
| Article | /blog/post-1 | +8 pts | Helps AI understand authorship, freshness, and content authority |
| FAQPage | /faq | +8 pts | Directly feeds AI Q&A engines, increases citation probability |
| BreadcrumbList | All pages | +5 pts | Provides hierarchical context for AI content understanding |

Output file: schema-{domain}.json

Installation:
  1. Copy the relevant <script> blocks into each page's <head>
  2. Validate at https://validator.schema.org/
  3. Test at https://search.google.com/test/rich-results
```

---

## Quality Gates

1. **Valid JSON**: All generated JSON-LD must be syntactically valid
2. **Required properties**: Every schema must include all required properties per schema.org spec
3. **Real data only**: Never invent data — if a field cannot be extracted, omit it or mark as `TODO`
4. **No duplicate schemas**: If a schema type already exists on a page, suggest improvements instead of adding duplicates
5. **URL validation**: All URLs in schema must be absolute and verified accessible
6. **Rate limiting**: 1 second between requests to the same domain
7. **Respect robots.txt**: Do not fetch pages blocked by robots.txt

---

## Business Type Priority

Different business types need different schemas first:

| Business Type | Priority Schemas |
|---------------|-----------------|
| **SaaS** | Organization, WebSite, FAQPage, HowTo, Article |
| **E-commerce** | Organization, Product, BreadcrumbList, FAQPage, WebSite |
| **Publisher** | Organization, Article, Person, BreadcrumbList, WebSite |
| **Local** | LocalBusiness, FAQPage, BreadcrumbList, WebSite |
| **Agency** | Organization, Person, FAQPage, Article, WebSite |
