Fixing Conflicting Values and Types Between JSON-LD Blocks
Several JSON-LD blocks on one page are normal. The trouble starts when two of them describe the same thing and disagree: one product block says £49 and another says £54, one article block says BlogPosting and another says NewsArticle, one rating counts 12 reviews and another 31.
Search engines then have to guess which statement to believe, and nothing guarantees they pick the one your visitors see. This guide is about the values themselves: finding every place the page contradicts itself, deciding which value is true, and ending up with one consistent description of each thing.
What counts as a conflict
A conflict needs two things: two descriptions of the same real-world thing, and at least one value or type that disagrees between them. Plenty of multi-block pages have no conflict at all. A page with an Organization block, a BreadcrumbList block and a Product block is perfectly tidy, because each block describes something different.
Conflicts fall into two families:
- Value conflicts. The same property holds different values: price, currency, availability, rating count, headline, publication date, logo, telephone number, opening hours. These are the ones that produce visibly wrong results, such as an old price under a search listing.
- Type conflicts. The same thing is given incompatible types, or the page has two
different candidates for its main entity. An article labelled
Articlein one block andNewsArticlein another, or a page that is simultaneously aProductand aServicefor the same offering.
The JSON Checker detects conflicting types as part of its checks. Value conflicts are found by comparing blocks that describe the same entity, which this guide walks you through. Where the underlying cause is several plugins or apps each writing markup, the separate guide on plugin schema conflicts deals with switching sources off; this one deals with getting the facts straight whatever the source.
The conflicts that turn up most
| Conflict | Typical cause | What it risks |
|---|---|---|
| Two prices for one product | The theme outputs the default variant's price, an app outputs the lowest price, or one block includes VAT and the other does not | The wrong price in search, and a mismatch with your Merchant Center feed |
| Different availability | One block is cached and still says in stock after the item sold out | Shoppers clicking through to an unavailable item |
| Two sets of ratings | The platform's built-in reviews and a review app both output aggregateRating
with different counts | Stars that do not match the page, which review guidelines treat as misleading |
| Rival article types | The SEO plugin says Article, the theme says BlogPosting,
a news plugin says NewsArticle | An unclear main entity and duplicate article items in testing tools |
| Different dates | One block uses the original publish date, another the last modified date
as datePublished | The wrong date shown next to the result |
| Two versions of the business | The theme's Organization uses the trading name and old phone number; the SEO plugin's LocalBusiness uses the legal name and the new number | Inconsistent business details across search features |
| Two breadcrumb trails | The theme and the SEO plugin both output a BreadcrumbList with different paths | An unpredictable breadcrumb in the search result |
| JSON-LD against Microdata | An older theme's itemprop attributes still sit
in the HTML alongside newer JSON-LD | Two formats telling different stories, one of which nobody maintains |
The common thread is that nobody decided which system owns which fact. Each tool is individually doing its job, but they read from different fields, run at different times or apply different rules.
What search engines do with contradictions
Google does not publish a rule for choosing between conflicting structured data, and you should not assume one. In testing tools you will usually see both items listed separately, for example two Product items for one page, each assessed on its own. What appears in search may reflect either, and may change from one crawl to the next.
Some consequences are more predictable:
- Merchant listings compare prices. Google checks product data against what it sees on the page and in any Merchant Center feed. A structured data price that disagrees with the page or the feed can lead to warnings or a product being disapproved in Merchant Center.
- Review markup has to reflect the page. Google's review snippet guidelines expect ratings to match reviews visible to the user. Two different counts on one page means at least one of them does not.
- Other readers see the contradiction too. AI assistants, comparison tools and browser extensions read the same markup, and a page that gives two answers to "how much is it?" is less likely to be quoted accurately.
None of this is a penalty in the sense of a manual action for having two blocks. It is simply unreliable, and the fix is to make the page say one thing.
Finding conflicts the source view hides
The HTML source is only part of the picture. Several common setups produce conflicts that only appear in the rendered page:
- Script-injected blocks. Review apps, tag manager tags and some consent tools add
JSON-LD after the page loads. View source does not show them; the Elements panel in developer tools does.
Search for
application/ld+jsonin the Elements panel and compare the count with view source. - Variant switching. On a product with sizes, the server outputs markup for the default variant. A script may then update the visible price when the shopper chooses another size while the markup stays the same, or a second script may add a block for the selected variant.
- Microdata and RDFa. These live in attributes on ordinary HTML tags, not in a script
block. Search the source for
itemtype=andtypeof=to find them. The Schema Markup Validator lists entities from all three formats together, which makes cross-format conflicts easy to spot. - Logged-in and cached variants. A page cache can serve yesterday's block while a fresh block is generated for logged-in editors. Check the page logged out, in a private window, as the public sees it.
Deciding which value is right
The answer is almost never "whichever block looks more complete". Structured data should describe what the page shows, so the visible page is the reference for every value. Where the page itself is ambiguous, go back to the system of record:
| Value | Source of truth | Watch out for |
|---|---|---|
| Price and currency | The price a shopper pays at checkout for the default selection, as shown on the page | VAT inclusion for UK shoppers, sale prices, and "from" prices on multi-variant items |
| Availability | Live stock status in the shop system | Cached blocks that lag behind stock changes |
| Rating and review count | The reviews actually displayed on this page | Counts that include other products, other languages or imported reviews not shown |
| Article type | What the content is: a blog post, a news report, a technical guide | Plugin defaults applied to every post regardless of content |
| Dates | The publish and update dates shown on the article | Modified dates used as published dates, and time zone differences |
| Business name, phone, address | Your contact page and Google Business Profile | Old details kept in a theme option nobody remembers |
If the visible page is itself wrong, for example it shows an out-of-date phone number, fix the page first. Structured data that faithfully matches a wrong page is still wrong.
The fix, step by step
Step 1
Collect every block, including rendered ones
Run the JSON Checker on the page, then open developer tools and search the Elements
panel for application/ld+json, itemtype= and typeof= so you catch
script-injected JSON-LD, Microdata and RDFa as well. Do this logged out in a private window. Copy each
block into a document and note which tool produced it, using class names, HTML comments or the order
in which blocks appear as clues.
Step 2
Group the blocks by the thing they describe
Sort the entities into groups that refer to the same real thing: all descriptions of
this product, all descriptions of this article, all descriptions of your business. Use the name, the
address, the SKU and any shared @id to decide. Entities that describe different things,
such as a product and its breadcrumb trail, are not in conflict and can be left alone. Only groups with
two or more members need attention.
Step 3
Compare the values field by field
For
each group, lay the entities out in a spreadsheet with one column per block and one row per property,
including @type. Highlight every row where the values differ, and note rows where only one
block has a value at all. This turns a vague sense that the page has duplicate schema into a precise
list of contradictions, such as a price, a rating count and a type, that you can resolve one by one.
Step 4
Settle each value against the visible page
For every highlighted row, find the value a visitor actually sees on the page and treat that as correct. Check price against the checkout for the default selection, availability against live stock, ratings against the reviews displayed, dates against the byline and business details against your contact page. Where the page itself is out of date, correct the page first. Write the settled value into a final column so you have a single agreed description.
Step 5
Choose one description for each entity
Decide which source will own each entity from now on, normally the one that reads directly from the system holding the true values, such as the shop platform for price and stock. Switch off the other sources for that entity in their settings, or remove the markup from the template, so only one block describes it. For type conflicts, keep one node and give it the single most accurate type, or an array where the thing genuinely is both.
Step 6
Move the useful extras into the surviving block
The block you removed may have held facts the surviving one lacks, such as a GTIN,
a return policy or a list of social profiles. Add those to the surviving description, either through
the owning tool's settings or by extending its node with a small block that uses the same @id
and adds only the missing properties. Never add a property that repeats one the owner already outputs,
or the conflict simply returns in a new form.
Step 7
Retest once caches have cleared
Purge the page cache, any CDN cache and any optimisation plugin cache, then run the JSON Checker again and check the Rich Results Test lists one item for each entity. Compare the final values with your spreadsheet. Test a variant switch and an out-of-stock product if you run a shop, because those are the moments when conflicts tend to reappear. Recheck after any plugin, theme or app update.
Merging two product blocks: an example
A shop page for a fictional tile retailer carries a theme Product block with a price excluding VAT and no rating, and an app Product block with the correct VAT-inclusive price, a rating and no GTIN. The visible page shows £54.00 including VAT and 18 displayed reviews averaging 4.6. After settling each value and keeping one owner, the single remaining block looks like this:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"@id": "https://www.example.co.uk/products/sage-metro-tile/#product",
"name": "Sage Metro Wall Tile, 20 x 10 cm (box of 50)",
"image": "https://www.example.co.uk/images/sage-metro-tile.jpg",
"sku": "BT-SMT-2010",
"gtin13": "5012345678917",
"brand": { "@type": "Brand", "name": "Brackenfield Tiles" },
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": 4.6,
"reviewCount": 18
},
"offers": {
"@type": "Offer",
"url": "https://www.example.co.uk/products/sage-metro-tile/",
"price": "54.00",
"priceCurrency": "GBP",
"availability": "https://schema.org/InStock"
}
}
</script>
The GTIN came from the theme block, the rating from the app, and the price from the visible page. Nothing in the final block contradicts anything else the page says.
Type conflicts need a different kind of decision
Two blocks that call the same article Article and BlogPosting are not really
disagreeing, because a BlogPosting is a kind of Article. Keep the more specific type on one node and
drop the other. Two types that are both true but unrelated, such as Book and Product
for a book in an online shop, belong together in one node as an array. Types that cannot both be true,
such as Product and Service for the same boiler installation, need a decision
about what the page actually offers; the other type should go.
Keeping one version of the truth
- Write down who owns what. A short list such as "SEO plugin: Organization, WebSite, Article; shop platform: Product and Offer; review app: ratings only" prevents most conflicts before they start.
- Turn off markup when installing apps. Many review, shop and events apps add structured data by default. Check the settings as soon as you install one and switch it off if another tool already covers that entity.
- Retire old formats deliberately. When moving from Microdata to JSON-LD, remove the
itempropattributes in the same release, so the two cannot drift apart. - Test the awkward moments. Price changes, sales, sell-outs and article updates are when a lagging block starts to disagree. Spot-check a page after each.
The JSON-LD Fixes hub covers the other checks. If the competing block came from an AI generator, see duplicate AI schema.
1. Is having two JSON-LD blocks on a page a problem in itself?
No. Pages commonly carry several blocks, one from the SEO plugin, one from the theme and one from an app, and that is perfectly valid. It only becomes a problem when two blocks describe the same thing and disagree about it, such as two Product entities with different prices or two article entities with different types. Blocks that each describe something different, like a product and its breadcrumb trail, can happily coexist without any change.
2. Which price should my Product schema show when prices differ?
The price a shopper actually pays for the default selection, as shown on the page. For UK consumers that normally means including VAT. If the product has variants at different prices, the structured data for the page should match what the page displays when it first loads, and an AggregateOffer with low and high prices can describe a range. Make sure your Merchant Center feed, the visible price and the markup all agree, because mismatches can cause listing problems.
3. Will Google penalise my site for conflicting structured data?
Having two conflicting blocks is not in itself a reason for a manual action. The practical risks are that Google may show the wrong value, may treat the markup as unreliable, or may flag mismatches in Merchant Center. Review markup is different: if ratings in structured data do not match the reviews shown on the page, that goes against Google's review snippet guidelines, and spammy structured data can lead to a manual action. Resolving the conflict removes these risks.
4. Should I use Article, BlogPosting or NewsArticle?
Use the one that describes the content most precisely, and only one. A post on a company blog is a BlogPosting. A report on current events from a news publisher is a NewsArticle. A long how-to guide can simply be Article, or TechArticle if it is technical. All three are types of Article, so choosing the more specific one never loses anything. The conflict to avoid is two blocks giving the same piece of writing different types.
5. The Rich Results Test shows two Product items. Which one does Google use?
Google does not publish a rule for choosing between them, and you should not rely on either being picked consistently. Expand both items in the test and compare them to see which fields differ. Then decide which tool should own the product markup, switch off the other one and move any useful extra fields into the surviving block. Once only one Product item appears in the test and its values match the page, the question no longer arises.
6. Can Microdata and JSON-LD conflict with each other?
Yes. Search engines read Microdata, RDFa and JSON-LD, so a page with Microdata attributes left over from an older theme and a newer JSON-LD block is describing its content twice. If the two disagree, perhaps because only the JSON-LD was updated after a price change, you have a conflict just as you would with two JSON-LD blocks. Search the source for itemtype and itemprop, and remove the old format when you move to the new one.
7. How can I stop conflicts coming back after I fix them?
Agree which tool owns each type of entity and write it down, switch off structured data in any new app or plugin that would duplicate an owned entity, and remove old Microdata when you adopt JSON-LD. Then spot-check the pages most prone to drift, such as product pages after a price change or sell-out and articles after an update. Running the JSON Checker on each template after updates catches most regressions quickly.
The JSON Checker parses every JSON-LD block on your page, validates the syntax, checks each type against schema.org, verifies required fields, detects conflicting types and tests the result against Google rich result criteria.
Open JSON-LD Fixes →