You run your homepage through the Rich Results Test and it lists your organization twice. Or a validator flags a duplicate WebSite block. Or an AI describes your business with a founding year you retired from the site two redesigns ago, and you cannot work out where it is still getting that from.
This is almost never one plugin misbehaving. It is two schema sources running at the same time, each unaware of the other, both writing JSON-LD into your pages. It is common on WordPress specifically, because schema output is a feature of SEO plugins, dedicated schema plugins, a lot of premium themes, and some page builders, and it is easy to end up with two of them switched on without ever deciding to.
Here is how to tell what you have, why two copies is worse than one, and how to get back to a single clean source. If you are chasing a specific validator error rather than a duplication problem, the guide to common schema markup errors covers those one by one; this post is about the case where the markup is valid and there is simply too much of it.
How you end up with two
Four routes account for most cases.
An SEO plugin plus a dedicated schema plugin. You run Yoast, Rank Math, or All in One SEO for titles, meta descriptions, and sitemaps, and at some point you added Schema Pro, "Schema & Structured Data for WP," or hand-written JSON-LD through a snippet plugin because you wanted better structured data. Now both are emitting Organization, WebSite, and an Article block on every post.
A theme that ships its own schema, plus an SEO plugin. Plenty of premium themes output their own Organization, breadcrumb, and article markup. Activate any SEO plugin alongside it and you have two sources before you have configured anything.
A migration that is half done. You are moving from Yoast to Rank Math, or the other way. For the whole window where both plugins are active, both are assembling and printing a complete schema graph.
A block that injects its own script. Some plugins' FAQ and HowTo blocks write a <script type="application/ld+json"> directly into the post content, separately from the plugin's main head output. So even a single plugin can put two blocks on one page: one in the <head>, one in the body.
What two copies actually breaks
It rarely takes the site down, which is exactly why it sits unnoticed for months. What it does is quieter.
Duplicate entities. Two Organization nodes, with different identifiers or none, slightly different names, two logo URLs, two descriptions. A machine reading the page finds two companies with similar details and has to decide whether they are one business or two. That guess is where an AI system starts describing you wrong. In readiness terms this is a duplicate-entity graph break, and whether your identity is declared cleanly and connected is worth close to half of an AI readiness score.
Contradictions. One source declares a foundingDate, the other does not. One lists a telephone, the other lists a different one. One plugin's Article names a publisher that resolves to a real declared organization, the other's names a publisher that is declared nowhere. A reader now has conflicting facts about the same business and no way to rank them.
The strongest signal you have, wasted. The entire reason to publish structured data is to remove the guesswork about who you are and what a page means. Two uncoordinated copies of that data put the guesswork back, and often make things worse than having none, because a machine that sees nothing knows it needs to look elsewhere, while a machine that sees two conflicting declarations may just pick one.
Unreliable rich results. When Google finds two blocks describing the same thing, it may use one, use the other, or trust neither. If your rich results have been flickering in and out, duplicate markup is a common cause.
What this looks like in practice, for an AI system: it crawls your page, extracts the structured data, and finds two Organization records. If they agree on everything, the redundancy is merely wasteful. If they disagree on anything, a name, a logo, a phone number, a founding year, the model has to reconcile them, and it does that with whatever else it has picked up about you from directories and third-party pages. The version it settles on may be neither of the two on your site. You have handed it a decision to make that a single, clean declaration would have made for it.
The breadcrumb case, which is the most common one
If you only ever find one duplicate, it will probably be BreadcrumbList. A large share of premium themes output their own breadcrumb schema, tied to the visible breadcrumb trail they render near the top of the page. Every major SEO plugin also outputs BreadcrumbList. Turn both on, which is the default state on many sites, and every page has two breadcrumb graphs describing the same path.
It is worth calling out separately because the fix is slightly different. Breadcrumb schema is usually attached to a visible page element, so you generally want to keep whichever breadcrumb you are actually displaying and disable the other one's markup. If your theme renders the breadcrumb trail your visitors see, keep the theme's schema and turn the plugin's off. If you use the plugin's breadcrumb widget or shortcode, do the reverse. The mistake is disabling the markup for the breadcrumb you are still showing, which leaves a visible trail with no structured data behind it.
How to see what you have got
View the page source and count the blocks. Right-click, "View Page Source," which is the raw HTML your server sent, not the rendered inspector. Search the page for application/ld+json. Every hit is a JSON-LD block. On a simple page you would expect one. More than that is worth opening up.
Search the whole page, not just the head. Some blocks are printed in wp_head, some are injected into the middle of the post content by a block or widget, and some land in wp_footer. A quick scroll to the <head> will miss the other two.
Read each block's @type and work out where it came from. If Organization appears twice, or WebSite appears twice, or you see two Article blocks on one post, and they look like they were generated by different tools, that is your conflict. Different formatting, different property names for the same thing, and different @id conventions are all tells.
Put a few pages through the validators. The Rich Results Test and the Schema.org validator both list every entity they detect. Two organizations in that list, or an explicit duplicate warning, confirms it.
Check more than the homepage. Test the homepage, a blog post, and a product or service page. Conflicts often appear on one page type and not another. A very common pattern is a site that is clean everywhere except posts that contain an FAQ block.
How to fix it: get down to one source
The rule is simple and the execution is fiddly. Exactly one thing should own your schema output.
1. Decide which source stays. Judge the candidates on three things. Does it output a single connected @graph, where your organization is declared once with a stable @id and every other node references it, rather than reprinting a copy on every page? Does it pick the right, specific @type for each page rather than labelling everything WebPage? And does it stay current as your content changes rather than freezing whatever was true when you set it up? Whichever source wins those, keep it. If that is a dedicated schema or entity tool, your SEO plugin carries on doing titles, meta, sitemaps, and redirects untouched.
2. Turn off schema in the others, not the whole plugin. You want to keep the SEO plugin's other features.
- Rank Math: the cleanest switch. Go to Rank Math, then Dashboard, and turn off the Schema (Structured Data) module. Or, to keep it for some content, go to Titles & Meta, open each post type, and set its schema type to None.
- All in One SEO: open Search Appearance, then each content type, and disable the schema markup or rich snippet output there.
- Yoast: there is no single global switch. Yoast's schema is wired through its Search Appearance settings, where you set the schema type per content type, and stopping it entirely usually means using the
wpseo_json_ld_outputfilter, which is a few lines in a code-snippet plugin, or a dedicated compatibility integration that applies that filter for you. The specific case of keeping Yoast for meta while another tool owns schema has its own walkthrough. - A theme: look in the theme's own SEO or schema options first. If there is no toggle, you are choosing between a small child-theme change to remove its output and simply treating the theme's
Organizationblock as the canonical one and disabling the plugin's instead.
3. Deal with the schema that lives in your content. FAQ and HowTo blocks that write JSON-LD into the post body will keep doing that even after you disable a plugin's head output, because the script is saved in the post content itself. Either stop using those specific blocks, or rely on your chosen schema source to strip them, which some tools do automatically by cleaning the content late in the render.
4. Re-check the same pages. View source again on the homepage, a post, and a service or product page. Confirm one block per entity, and run the two validators again to be sure.
5. If you are deliberately keeping two, connect them. It is uncommon, but if a theme owns your WebSite node and a plugin owns everything else, make both use the same @id so the whole thing reads as one graph instead of two. The rules for combining types on a page correctly are in the guide to multiple schema types on one page.
One site, walked through
Take a composite example, assembled from patterns that recur rather than one real site: a mid-size professional services firm on a premium multipurpose theme, with Yoast installed for meta and sitemaps, and a schema snippet plugin added a year ago by a contractor to "add FAQ schema."
View source on the homepage shows three application/ld+json blocks. The theme prints an Organization and a WebSite node with the company name and the theme developer's default logo path, which was never changed. Yoast prints its own graph: an Organization with the correct logo, a WebSite with a SearchAction, a WebPage, and a BreadcrumbList. The snippet plugin prints a standalone FAQPage. So the page declares the organization twice, with two different logos, and the website twice.
On a service page, view source shows the theme's Organization again, Yoast's full graph again, and, because this page has an FAQ block, a second FAQPage that the snippet plugin injected into the post content.
The fix is one decision and three actions. The decision: Yoast's graph is the most complete and it connects its nodes by @id, so Yoast owns schema. The actions: disable the theme's schema in its options panel, which turns out to have a toggle under its SEO settings; remove the snippet plugin, since Yoast already generates FAQ schema from the block; and re-crawl. The re-check shows one Organization, one WebSite, one FAQPage per page that needs it, all referenced by consistent identifiers.
Nothing here was a bug. Three tools were each doing their job, and no one had told two of them to stop.
The migration case deserves its own note
If you are switching from one SEO plugin to another, sequence it deliberately: turn off the old plugin's schema output before you switch the new one on, not after. In any window where both are active, every page on your site is serving a doubled graph, and a crawler that visits during that window records the messy version. On a fast-crawling AI retrieval bot, that window does not need to be long.
Why it comes back
Getting down to one source is not permanent, because the events that reintroduce a second one are routine. A theme update can re-enable a schema toggle you had switched off, or add schema output to a theme that never had it. A new plugin installed for something unrelated turns out to include its own structured data, on by default. A staging site gets restored over production and brings an old plugin set with it. A contractor adds a snippet plugin to solve one page's FAQ markup and does not know the site already has a schema source.
None of these announce themselves, and the symptom, a second Organization block, looks identical to the one you already fixed. The practical answer is to re-check your page source after any theme or plugin change that could touch output, and to run a full structured-data check a few times a year regardless. It is the same drift that affects every other part of a site's machine-readability: nothing stays fixed on its own because nobody is watching the markup.
Common Mistakes
Assuming "duplicate schema" means a plugin is buggy. It almost always means two sources are running, and the fix is to remove one, not to troubleshoot either.
Deactivating the entire SEO plugin to stop its schema. You lose your sitemaps, redirects, and meta tags to solve a structured-data problem. Disable the schema feature specifically.
Checking only the homepage. The homepage is often the one page someone configured carefully. The conflict is usually louder on posts and product pages.
Fixing the head output and missing the rest. Block-injected JSON-LD in post content, and anything printed in the footer, survive a fix aimed only at wp_head. Search the full page source.
Keeping both "to be safe." Two half-right descriptions of your company are worse than one, because a machine cannot tell which to believe. A confident wrong answer is harder to recover from than an honest gap, and that is exactly what two conflicting Organization blocks produce.
Not re-testing. Caching, in particular, will show you the old doubled output for a while after the fix is correct. Clear the cache, then re-check.
Frequently Asked Questions
AI Schema Gen takes ownership of your schema output and suppresses the duplicate blocks from Yoast, Rank Math, and All in One SEO automatically, so every page carries one connected graph instead of two competing ones. Check what your site is publishing, free at aischemagen.com.
Is your site ready for AI?
Get a free readiness score in under a minute. No signup, no card.
Run the free check