/ AI Schema Fixes / Duplicate Schema

How to Fix Duplicate Schema Generation

When you add an AI schema generator to a site that already runs Yoast, Rank Math, or any SEO plugin, you get two competing JSON-LD outputs on the same page. Both describe the same Article — often with different data. Google and AI engines see conflict, lower trust, and may discard both. This guide covers detection, consolidation, and the @graph pattern that lets multiple sources coexist cleanly.

1. Detect duplicate schema

Step 1
View source
Browser → View Page Source → Cmd/Ctrl+F → search application/ld+json. Count occurrences. 3+ blocks warrants investigation.
Step 2
Extract and compare
curl -s https://example.com/blog/post-1 | \
  python3 -c "
import json, re, sys
html = sys.stdin.read()
blocks = re.findall(r'<script type=\"application/ld\+json\">(.+?)</script>', html, re.DOTALL)
print(f'Found {len(blocks)} JSON-LD blocks')
types_seen = {}
for i, b in enumerate(blocks):
    try:
        data = json.loads(b)
        items = data if isinstance(data, list) else [data]
        for item in items:
            graph = item.get('@graph', [item])
            for entity in graph if isinstance(graph, list) else [graph]:
                t = entity.get('@type', 'unknown')
                types_seen.setdefault(str(t), []).append(i)
    except:
        pass
print('Entity types and which blocks contain them:')
for t, blocks_with in types_seen.items():
    marker = ' DUPLICATE' if len(blocks_with) > 1 else ''
    print(f'  {t}: blocks {blocks_with}{marker}')
"

2. Three common conflict patterns

Pattern 1: Yoast + AI generator both output Article

<!-- Yoast -->
<script type="application/ld+json">
{
  "@context":"https://schema.org",
  "@type":"Article",
  "headline":"How to choose a CRM",
  "author":{"@type":"Person","name":"Admin"}
}
</script>

<!-- AI generator -->
<script type="application/ld+json">
{
  "@context":"https://schema.org",
  "@type":"Article",
  "headline":"How to choose a CRM",
  "author":{"@type":"Person","name":"Jane Baker","jobTitle":"Sales Lead"}
}
</script>
<!-- Two Articles. Different authors. Google picks one or neither. -->

Pattern 2: Plugin emits BlogPosting, generator emits Article

<!-- Different @type, same entity -->
{"@type":"BlogPosting", "headline":"..."}  <!-- from plugin -->
{"@type":"Article", "headline":"..."}     <!-- from generator -->
<!-- BlogPosting is subtype of Article. Two entities, one truth. -->

Pattern 3: Plugin Organization vs generator Organization

<!-- Plugin -->
{"@type":"Organization","name":"Acme Corp","logo":"https://example.com/logo.png"}

<!-- Generator (no logo) -->
{"@type":"Organization","name":"Acme"}
<!-- Two Organization entities. Trust signal weakens. -->

3. Strategy 1: Disable one source

The simplest fix:

# Yoast: Settings → Search Appearance → Content Types → "Display this content type in search results" + schema toggle
# Disable schema for the post type your AI generator handles

# Rank Math: Titles & Meta → Post Types → choose type → "Schema Markup" → None

# Then AI generator is the only source for that content type

4. Strategy 2: Consolidate via @graph

Better for sites needing both site-wide schema (Organization, WebSite) AND content-specific schema:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Acme Corp",
      "url": "https://example.com",
      "logo": {
        "@type": "ImageObject",
        "url": "https://example.com/logo.png"
      }
    },
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "url": "https://example.com",
      "name": "Acme",
      "publisher": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Article",
      "@id": "https://example.com/blog/post-1#article",
      "headline": "How to choose a CRM",
      "datePublished": "2026-01-15T09:00:00Z",
      "author": {
        "@type": "Person",
        "@id": "https://example.com/authors/jane-baker#person",
        "name": "Jane Baker"
      },
      "publisher": { "@id": "https://example.com/#organization" },
      "isPartOf": { "@id": "https://example.com/#website" }
    },
    {
      "@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": "How to choose a CRM", "item": "https://example.com/blog/post-1" }
      ]
    }
  ]
}
</script>

One block, multiple entities, explicit relationships via @id references. Both your plugin and AI generator should feed into building this single graph.

5. Strategy 3: Split by entity type

Plugin handles site entities, AI generator handles content entities. Each emits only its assigned types:

# Config
[plugin]
emit_types = ["Organization", "WebSite", "BreadcrumbList"]
disable_types = ["Article", "BlogPosting", "Product", "Recipe", "HowTo", "FAQPage"]

[ai_generator]
emit_types = ["Article", "BlogPosting", "Product", "Recipe", "HowTo", "FAQPage"]
disable_types = ["Organization", "WebSite", "BreadcrumbList"]

# Each source emits only what it's assigned
# Reference the other's entities by @id
# Multiple JSON-LD blocks but no duplicate entities

6. Common WordPress fix

// In your theme's functions.php
// Disable Yoast Article schema, keep its Organization
add_filter('wpseo_schema_graph_pieces', function($pieces, $context) {
    return array_filter($pieces, function($piece) {
        $class = get_class($piece);
        // Remove Article-related pieces
        return !preg_match('/Article|BlogPosting/i', $class);
    });
}, 10, 2);

// Then your AI-generated schema is the only Article source

7. Validate

Step 1
Rich Results Test
search.google.com/test/rich-results — should report ONE Article, ONE Organization, ONE BreadcrumbList. Multiple of the same type = duplicate.
Step 2
Schema validator
validator.schema.org — flags ambiguous @id references and conflicting entity definitions.
💡 The @graph + @id pattern is the gold standard for sites with multiple schema sources. Each piece references others by @id rather than re-declaring them. Yoast and modern SEO plugins already use this pattern internally — extend it to include AI-generated content schema rather than emitting separately.

🤖 Re-run AI Schema Generator

Verify single consolidated graph per page.

Run AI Schema Generator →
Related Guides: AI Schema Fixes  ·  Fix Schema References  ·  Fix JSON-LD Coverage  ·  Fix Rich Results
💬 Got a problem?