Breadcrumb JSON-LD Does Not Match the Visible Breadcrumb

Rich Results Test passes but Search Console flags breadcrumb mismatches, or the breadcrumb in SERP looks wrong. How to align JSON-LD with what users see.

Your page shows the breadcrumb “Home → AI Tools → ChatGPT issues.” Rich Results Test says the BreadcrumbList JSON-LD is valid. But Search Console’s Enhancements report flags it with warnings, or the SERP breadcrumb shows fewer levels or different wording. The cause is usually that JSON-LD is generated independently from the visible UI — different data sources, different label conventions, different locale handling. Google’s rule is that JSON-LD must match the visible breadcrumb in label, URL, and order. Even if both individually validate, mismatch demotes the rich result.

Common causes

Ordered by hit rate, highest first.

1. JSON-LD uses slugs while UI uses display names

{ "name": "ai-tools", "item": "https://site.com/category/ai-tools/" }

Visible UI shows “AI Tools” (with capitalization and space). JSON-LD says ai-tools (slug). Google detects mismatch.

How to spot it: Compare visible label to JSON-LD name exactly. Capitalization matters; spacing matters.

2. URL casing or trailing slash differences

JSON-LD: https://site.com/Category/AI-Tools. Visible link: https://site.com/category/ai-tools/. Same logical destination, different strings.

How to spot it: Inspect anchor tag href vs JSON-LD item. Must be byte-identical.

3. UI omits homepage; JSON-LD includes it (or vice versa)

UI shows “AI Tools → ChatGPT issues” (no home). JSON-LD has Home at position 1. Or UI has Home but JSON-LD doesn’t.

How to spot it: Count visible breadcrumb items vs. JSON-LD itemListElement.length. Should be equal.

4. Localization: JSON-LD untranslated

A non-English locale page shows translated breadcrumb labels in the UI but the JSON-LD still emits the English originals. Google flags the mismatch.

How to spot it: Open a non-default-language page. Compare JSON-LD name fields to visible UI labels.

5. Extra hidden levels for “SEO”

Someone added phantom intermediate levels in JSON-LD (“Home → AI → Tools → AI Tools → ChatGPT”) thinking it improves SEO. UI shows fewer levels. Google considers this misleading and demotes.

How to spot it: Count JSON-LD positions. If > visible UI count + 1, you have phantom levels.

6. BreadcrumbList ordering wrong

position: 1, 2, 3 should map to root → leaf. Reversed or shuffled breaks the rich result.

How to spot it: Check position field in each item. Position 1 should be Home (or root), increment by 1 per level, end at the current page.

Shortest path to fix

Step 1: Compare visible breadcrumb to JSON-LD

Manual diff for one page:

# Extract visible breadcrumb anchor texts and hrefs
curl -s "https://site.com/article/" | grep -oP '<nav[^>]*aria-label="breadcrumb[^>]*>[\s\S]+?</nav>'

# Extract JSON-LD breadcrumb
curl -s "https://site.com/article/" | grep -oP '"@type":"BreadcrumbList[\s\S]+?</script>'

Compare position-by-position.

Step 2: Generate both from one source

Refactor your layout to compute the breadcrumb once and emit both UI and JSON-LD:

---
const breadcrumb = [
  { name: 'Home', url: '/' },
  { name: 'AI Tools', url: '/category/ai-tools/' },
  { name: article.title, url: Astro.url.pathname },
];

const jsonLd = {
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": breadcrumb.map((b, i) => ({
    "@type": "ListItem",
    "position": i + 1,
    "name": b.name,
    "item": new URL(b.url, Astro.site).toString(),
  })),
};
---
<nav aria-label="breadcrumb">
  <ol>
    {breadcrumb.map((b, i) => (
      <li>
        {i < breadcrumb.length - 1
          ? <a href={b.url}>{b.name}</a>
          : <span>{b.name}</span>}
      </li>
    ))}
  </ol>
</nav>
<script type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>

One breadcrumb array → both representations. Guaranteed identical.

Step 3: Localize properly

Use your translation helper:

const breadcrumb = [
  { name: t('breadcrumb.home'), url: lang === 'en' ? '/' : `/${lang}/` },
  { name: t(`category.${article.category}`), url: `/${lang}/category/${article.category}/` },
  { name: article.title, url: Astro.url.pathname },
];

Both UI and JSON-LD now show translated labels.

Step 4: Validate via Rich Results Test

After fix, open the URL in Rich Results Test. All breadcrumb items should match the visible breadcrumb 1:1.

Step 5: Add CI check

// scripts/check-breadcrumb.mjs
import fs from 'node:fs';
import { parse } from 'node-html-parser';

for (const file of getDistHtmlFiles()) {
  const root = parse(fs.readFileSync(file, 'utf8'));
  const visibleLabels = root.querySelectorAll('nav[aria-label="breadcrumb"] a, nav[aria-label="breadcrumb"] span')
    .map(el => el.text.trim());
  const jsonLd = JSON.parse(root.querySelector('script[type="application/ld+json"]').text);
  const jsonLdLabels = jsonLd.itemListElement.map(i => i.name);

  if (JSON.stringify(visibleLabels) !== JSON.stringify(jsonLdLabels)) {
    console.error(`MISMATCH in ${file}\n  visible: ${visibleLabels}\n  jsonLd:  ${jsonLdLabels}`);
  }
}

Step 6: Resubmit to Google

After fix, Search Console → URL Inspection on representative URLs. Wait 1-2 weeks for Enhancement reports to clear.

When this is not on you

Search Console “Breadcrumbs” warnings can lag by days. Trust the source-code alignment first; the report will catch up.

Easy to misdiagnose as

Some teams add extra hidden levels in JSON-LD to “improve” SEO. Google considers this misleading and may suppress the rich result. Match what’s visible — no more, no less.

Prevention

  • Generate visible breadcrumb and JSON-LD from one helper function.
  • For bilingual sites, both layers must use the same translation source.
  • CI assertion: visible breadcrumb text matches JSON-LD name array exactly.
  • Don’t add phantom levels for SEO — Google sees through it.
  • When changing URL structure, regenerate both layers; don’t manually patch JSON-LD.

FAQ

  • Can I omit the homepage from breadcrumbs? Allowed but inconsistent UX. Usually include it as position 1.
  • Should the last item link to the current page? Optional — Google accepts both formats, but consistency within your site matters.

Tags: #SEO #Troubleshooting #Debug #Structured data #Breadcrumb #JSON-LD