Why Isn't My Schema Showing in Rich Results?
If the Rich Results Test says your markup is valid but nothing's showing up in Google, the cause is almost never "the schema is broken." It's one of a short list of specific, diagnosable reasons, and most of them have nothing to do with your JSON-LD syntax. This guide walks through each one in the order you should actually check them, so you can stop staring at a green checkmark and go straight to the real problem.
The thing to accept first: valid doesn't mean guaranteed
Google says this plainly, and it's worth internalizing before you troubleshoot anything else: structured data makes a page eligible for a rich result. It does not guarantee one will appear. Google's own general guidelines for structured data state this directly: using structured data enables a feature to be present, it does not guarantee that it will be present, because the algorithm tailors results based on many variables including search history, location, and device type, and may decide a text result is simply the better experience.
That's not a dodge, it's an accurate description of how the system works, and it reframes the whole troubleshooting process. Your job isn't to force a rich result into existence. It's to rule out every reason your markup might be ineligible or distrusted, so that if you're not appearing, it's genuinely Google's discretionary call rather than a fixable problem on your end.
With that framing, here's the actual diagnostic order.
Reason 1: Google simply chose not to show it
Start here, because it's the most common outcome and the easiest to misdiagnose as an error. Even flawless markup competes against other candidates for the same query: a review carousel, an image pack, an AI Overview, a plain text result, and Google picks whichever it judges best for that specific search, that device, that user. Your page can be perfectly eligible and still lose that slot, especially for competitive or generic queries.
You can't "fix" this the way you fix a syntax error. What you can do is make your markup more complete than the minimum, which tends to improve your odds without changing eligibility mechanics: richer, more specific structured data is a stronger candidate than the bare minimum, even though neither is guaranteed to win the slot.
Reason 2: your markup doesn't match what's visible on the page
This is the single most common fixable cause, and it's explicit in Google's own guidelines: structured data that isn't representative of the page's main content, or that's potentially misleading, is a documented reason rich results won't show, and Google specifically calls out incomplete review markup as an example, where a page includes multiple reviews but the schema doesn't mark up all of them, which misleads people expecting to see what the search result implied.
In plain terms: your AggregateRating says 213 reviews, but a visitor only sees 38 on the page. Your Product schema lists a price of $45, but the visible price now reads $52 after a sale ended. Your Event schema says the event is scheduled, but the page copy says it was cancelled last month. Any gap between what your JSON-LD claims and what a person actually sees is a mismatch, and Google treats mismatches as a trust problem, not a display bug.
This is exactly the mechanism we cover in detail for review stars specifically in our guide to getting star ratings, it's the number-one reason stars that once showed quietly vanish. The same principle applies to every schema type, not just reviews.
How to check it: open the live page, read what a visitor actually sees, then run it through the Rich Results Test and compare every value side by side: price, rating, date, status, availability. If anything disagrees, that's your fix, and it's usually the whole fix.
Why it happens most often: a redesign, a plugin update, or a migration changes what's rendered on the page but leaves the old schema block untouched. The two drift apart silently, because nothing errors, the markup is still syntactically valid, it's just no longer true.
Reason 3: you're emitting duplicate or conflicting schema
If more than one plugin, theme component, or manually-added script is generating schema for the same entity, you can end up with two different descriptions of the same thing on one page: two Organization blocks with different names, two Product prices, an SEO plugin's Review markup sitting next to a separately-added review widget's own JSON-LD. Google has to reconcile conflicting signals about the same entity, and when it can't confidently resolve which one is accurate, it commonly just doesn't show a rich result rather than guess.
How to check it: view source (not the browser inspector) and search for application/ld+json, count how many blocks appear and check whether any of them describe the same entity with different values. This is especially common on WordPress sites running an SEO plugin's built-in schema alongside a separate schema plugin, a page builder's own markup, or a manually pasted snippet from an old tutorial.
The fix: decide which source owns which part of the page, and disable or remove the overlapping output from the others. One coherent source per entity, not several competing ones.
Reason 4: your schema only exists in JavaScript, not the rendered HTML
Google's crawler renders pages, but rendering is a separate, delayed, resource-limited pass, and structured data that only gets injected client-side after JavaScript runs is a common way for schema to be technically present but effectively invisible to how Google processes it, especially at scale. This is a much bigger risk on decoupled or JavaScript-heavy builds than on standard WordPress, where your SEO plugin typically prints schema straight into the server-rendered HTML by default.
How to check it: view source on the live URL, not the DOM inspector, which shows the page after JavaScript has already run and will make broken setups look fine. If your JSON-LD block appears in view-source, it's server-rendered and this isn't your problem. If it's missing from view-source but present in the inspector, this is exactly your problem.
If you're running a headless or JavaScript-framework frontend, this failure mode is common enough that we wrote a dedicated guide to it, see schema for headless WordPress for the full mechanics of why it breaks and how to serve JSON-LD server-side.
Reason 5: the page or type isn't actually eligible
Sometimes the markup is flawless and the display logic is working exactly as designed, you're just not eligible for the result you're expecting. A few common versions of this:
Self-serving reviews. A business marking up reviews about itself using LocalBusiness or any Organization-type schema, including via an embedded third-party review widget, is explicitly ineligible for the star-rating rich result, no matter how clean the markup is. Product, Recipe, Course, Book, and SoftwareApplication pages are exempt from this rule because they're reviews of a specific item, not a business reviewing itself. We cover this rule and the legitimate path for local businesses in full in the star ratings guide.
A type with no rich result at all. Some schema types simply don't have a corresponding visual SERP feature, Service is the clearest example, and testing it in the Rich Results Test won't produce a rich-result preview no matter how complete your markup is, because there's nothing to preview. That's not a bug, it's the type doing its actual job, which is AI-readability and entity clarity rather than a visual snippet.
A deprecated feature. If you're marking up FAQPage expecting the FAQ rich result, that feature was fully retired in 2026, including the health and government eligibility that used to be an exception. The markup itself is still valid schema.org vocabulary and won't cause errors, but there's no rich result left to earn from it. HowTo was deprecated earlier, and several other types were narrowed in scope during 2025. If you're troubleshooting a "missing" rich result for one of these, the honest diagnosis is that the feature is gone, not that your markup is broken.
Wrong page for the type. Event schema belongs on the individual event's own page, not a calendar or listings page, Google's carousel links each card to a specific URL. Marking up a listings page instead is a placement mistake that looks like a display bug but is actually an eligibility one. Our Event schema guide covers this and the other Event-specific placement rules in depth.
Reason 6: Google hasn't recrawled the page yet
Search results aren't a live reflection of your site, they update as Google recrawls and reprocesses. If you just added or fixed your markup, there's a real lag before Google's index reflects the change, and it can be longer than people expect, especially on lower-crawl-priority pages.
How to check it: use the URL Inspection tool in Search Console to see the last crawl date and whether Google's indexed version reflects your current markup. If the "live test" in Search Console shows your fix correctly but the indexed version doesn't yet, you're simply waiting on a recrawl, request indexing if you need to accelerate it, but don't assume something's wrong just because the change hasn't propagated yet.
Reason 7: a page-quality or guideline violation is suppressing it
Beyond the markup itself, Google notes that content hidden from the user, or a page that doesn't meet the broader structured data guidelines or the guidelines for that specific feature, is a documented reason a rich result won't show even when the markup validates. This includes things like marking up content that exists in your JSON-LD but isn't genuinely visible anywhere on the page: accordion content that never renders, a review block for reviews you've since deleted from the page, or a price that only ever existed in the schema and never in your storefront.
How to check it: in Search Console, check the Manual Actions report specifically. A violation, including newer, stricter rules like the 2026 prohibition on fake or undisclosed incentivized reviews, can cause Google to ignore the structured data on affected pages entirely, which looks identical to "just not showing" until you check that specific report.
A worked example: spotting a mismatch
Here's the kind of drift that causes reason 2 more than anything else. Say a product page originally shipped with this:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Single-Origin Ethiopian Coffee Beans",
"offers": {
"@type": "Offer",
"price": "18.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.6",
"reviewCount": "213"
}
}Six months later, the product sold out, the price changed to $21, and 40 more genuine reviews came in, but this JSON-LD block, hand-pasted into a page template, never got touched. (If you're setting up Product schema from scratch rather than debugging an existing block, our Product schema guide covers the required and recommended fields.) Now the markup says InStock at $18 with 213 reviews, while the live page says out of stock at $21 with 253 reviews. Nothing in that block is malformed. The Rich Results Test will likely still pass it as valid. It just no longer describes the page it's sitting on, which is precisely the "not representative of the main content" reason Google names directly, and precisely why the rich result quietly stops appearing without any error ever surfacing.
This is the failure mode that hand-maintained schema is most prone to, and it's the one worth designing your workflow around avoiding.
Common mistakes that masquerade as "not showing"
Testing the wrong URL. Confirm you're testing the exact indexed URL, with or without trailing slash, www or not, since Google treats variants as distinct pages with potentially distinct crawl and index states.
Checking the DOM inspector instead of view-source. The inspector shows post-JavaScript output and will make a broken server-render setup look fine. Always view-source for what a crawler actually receives.
Assuming syntax validity means eligibility. The Rich Results Test checks whether your markup is well-formed and includes required properties. It does not check whether your content matches what's visible, whether you're duplicating another schema source, or whether Google will choose to display it. Passing validation is necessary, not sufficient.
Confusing "no rich result for this type" with "broken." If you're troubleshooting Service, Real Estate listings, or FAQ schema and getting no visual result, check first whether that type has a rich result to earn at all, or whether the feature you're expecting still exists.
Not checking Manual Actions. A policy violation silently suppresses structured data site-wide or page-wide, and it looks exactly like an ordinary display issue until you specifically check that report.
Forgetting the mismatch check after every content update. Prices, stock status, review counts, and event status change constantly. Every one of those changes needs to flow into the schema, or you're back to reason 2.
Diagnosing this on WordPress
The pattern behind most of these causes is the same: schema and content are two separate things that someone has to keep in sync, and the more manual that process is, the more places it can silently drift.
Check what's actually generating your markup first. Many WordPress sites run more than one source without realizing it: an SEO plugin's built-in schema, a page builder's own output, a leftover snippet from an old tutorial. View-source and count your application/ld+json blocks before troubleshooting anything else.
Confirm server-side rendering if you're on anything other than a standard WordPress theme setup, headless, a JavaScript-heavy page builder, or a custom frontend. View-source is the test; the DOM inspector will lie to you here.
Solve the drift problem structurally, not by remembering to update things. This is the piece that's hardest to sustain by hand and the reason mismatch (reason 2) is the most common cause on this whole list. AI Schema Gen generates schema from your page's actual live content rather than a static block someone wrote once, so your price, availability, review count, and status stay aligned with what's genuinely on the page as it changes, which removes the single biggest cause of "valid but not showing" before it ever happens. It also flags when a page's content and its generated schema type genuinely don't line up, so you catch a mismatch before it costs you a result rather than after.
Whichever tool you use, the underlying test doesn't change: does the markup match what a visitor sees, right now, on this exact page, and will it still match after your next content update.
Validating and monitoring
Google's Rich Results Test is your first stop for syntax and eligibility for supported types, but remember it only confirms validity, not display, a green result doesn't rule out reasons 1 through 7.
Search Console's Rich Result reports show what Google has actually parsed and validated across your site over time, and are the place to catch template-wide issues (a single broken component affecting every product page, for instance) rather than debugging one URL at a time.
The Manual Actions report is the specific place to rule out a policy violation, check it early if a rich result disappeared suddenly rather than never appearing at all.
View-source, always, not the DOM inspector, to confirm what's actually shipped to a crawler, especially when JavaScript rendering is anywhere in your stack.
A recurring manual check: pick a handful of key pages monthly and compare their live JSON-LD against what's visibly on the page. This is the single habit that catches reason 2 before Google does.
Frequently Asked Questions
Generate perfect schema in 30 seconds
AI Schema Gen handles everything automatically, free to start.
Get Started Free