What structured data actually does for you
Structured data does not make a page rank higher. It makes a page eligible for a different kind of result: stars under a product, a job card, a recipe with a cook time, a breadcrumb path instead of a bare URL. Google says plainly that markup is a signal about what the page contains, not a ranking boost, and that being eligible is not the same as being shown.
The practical payoff is the result area itself. A product result with a price and "in stock" occupies more vertical space and answers more of the question before the click. That is where the click-through difference comes from — not from a position change.
There is a hard rule underneath all of it: the markup has to describe what a visitor can see on the page. A price in the markup that is not on the page, a rating no one left, an FAQ that exists only in JSON — these are spam policy violations, and the penalty is losing rich results for the whole site, not just the page. Every field on this page is meant to be filled from content that already exists.
Which types still earn a rich result — and which ones ended
Google's search gallery documents roughly two dozen result types. The ones this page generates and that still produce something in Google Search are Article, Product, LocalBusiness, Organization, Event, Recipe, VideoObject, JobPosting and BreadcrumbList. Each type badge above carries the status we verified on 2026-09-06, because this is the part of SEO that changes most often.
- FAQPage: ended. Google stopped showing FAQ rich results on 7 May 2026, after narrowing them to a small set of authoritative sites in 2023. The markup is still valid Schema.org and other consumers still read it, but in Google Search it now earns nothing. Removing it is optional; expecting a result from it is not reasonable.
- HowTo: ended. It was removed from mobile results in August 2023, kept on desktop only, and then dropped. If you have HowTo markup on a tutorial, it is doing nothing for Google Search today.
- WebSite: partly. The sitelinks search box that WebSite + SearchAction used to produce was retired in November 2023. The type is still worth keeping, because WebSite's name and url are what Google uses to decide the site name shown above your title link.
- Person: only in context. A standalone Person node produces no rich result. It matters as the author of an Article and inside a ProfilePage, which is the type Google actually documents for profile results.
The generator does not block deprecated types. Structured data is read by more than Google — site search, internal tooling, aggregators and AI parsers all consume Schema.org — so there are legitimate reasons to publish FAQPage markup. The badge exists so that the decision is informed rather than accidental.
Required, recommended, and what happens when you skip one
The two levels are not equally serious. Missing a required property makes the item invalid for that rich result — Google parses it, decides it is not a valid Product, and shows an ordinary result. Missing a recommended property keeps the item valid but thins out what appears: a Product without availability can still show, but without the "in stock" line.
- Article has no required properties at all — Google's documentation says so explicitly. Everything on the Article form is a recommendation: headline, image, datePublished, dateModified, author. That does not make them optional in practice; author and dates are how Google judges freshness and provenance.
- Product is the opposite: name is required, and so is at least one of offers, review or aggregateRating. A product page with none of the three describes an object nobody can buy or rate, and Google treats it as ineligible. If you use offers, price and priceCurrency become required inside it.
- LocalBusiness requires name and a full PostalAddress. Latitude and longitude are recommended, and Google asks for at least five decimal places — 37.5 points at a district, 37.56654 at a building. An imprecise coordinate is worse than none, because it puts a pin on the wrong block.
- Event requires name, startDate and a location with a name and address. endDate is only "recommended", but for anything longer than a day it is effectively required — without it the listing looks like a one-day event.
Dates, durations and currencies: the formats that silently fail
Three value formats cause most of the validation errors in structured data, and none of them announce themselves. Dates use ISO 8601: 2026-09-06 for a date, 2026-09-06T10:00:00+09:00 for a moment in time. 06/09/2026 is ambiguous and rejected; 2026-9-6 is not ISO because the month and day need two digits.
Always include the offset when you include a time. Google's documentation warns that a datetime without a timezone is interpreted in the crawler's timezone, which is almost never yours — an event that starts at 19:00 in Seoul can be published as an afternoon event. Write +09:00, or Z if the value really is UTC.
Durations are ISO 8601 too, and they look strange the first time: PT30M is thirty minutes, PT1H30M is an hour and a half, PT1M54S is a minute and fifty-four seconds, P2D is two days. The P starts the period, the T separates date parts from time parts. "30 min", "1:30" and "90" are all invalid, and the field they sit in — cookTime, duration, totalTime — is exactly the one the rich result would have displayed.
Prices are plain numbers and currencies are three-letter ISO 4217 codes in capitals: price "19.99", priceCurrency "USD". Not "$19.99", not "19,990원", not "usd". The symbol belongs to the currency code, the thousands separator belongs to the display layer, and a range like "10-20" needs an AggregateOffer with lowPrice and highPrice instead.
Combining entities with @graph
A page usually describes more than one thing. A blog post is an Article, published by an Organization, on a WebSite, reachable through a BreadcrumbList. You can write four separate script tags — that is completely valid and Google reads them all — or you can write one script tag containing an @graph array with four nodes.
The reason to prefer @graph is references. Give the Organization node an @id such as https://example.com/#organization, and the Article's publisher becomes { "@id": "https://example.com/#organization" } instead of a second copy of the same name, url and logo. One definition, referenced everywhere, so the values cannot drift apart across templates.
Two rules keep a graph healthy. An @id must be unique inside the graph, and every @id you reference must actually be declared somewhere in it. A reference to a node that does not exist resolves to nothing and quietly removes the publisher, author or brand you thought you had declared. The validator on this page checks both, which is unusual — most free generators do not build graphs at all, so they never had to.
@id values are identifiers, not links that have to resolve. The convention is a URL with a fragment — /#organization, /#website, /page#article — because it is stable, readable and guaranteed unique per page. This tool never invents one for you: an @id you did not choose is an identifier nothing else will ever reference.
The JSON-LD errors that break markup silently
- A trailing comma. {"name": "A",} is valid JavaScript and invalid JSON. The whole block fails to parse, so the page goes from "structured data with one warning" to "no structured data" — and nothing on the page looks different.
- Single quotes. JSON-LD requires double quotes for both keys and string values. Copying a snippet out of a JavaScript file is the usual way this happens.
- An unescaped </script> inside a value. The browser's HTML parser closes the script block at that string, whatever the JSON says — the rest of your markup becomes visible page text. Writing the sequence as \u003C/script> avoids it, and this page does that for you whenever the script wrapper is enabled.
- Empty values. "description": "" and "image": [] are not neutral; validators report them as errors. Leave the property out instead. Everything this generator outputs already drops empty fields, which is why the JSON is sometimes shorter than the form.
- Relative URLs. "image": "/img/hero.jpg" cannot be resolved by a consumer that only has the JSON, so every URL in structured data must be absolute. The same applies to logo, sameAs, item and contentUrl.
- Markup that does not match the page. Reviews you wrote about yourself, a price that only exists in the JSON, an aggregateRating with no visible reviews. This is the one category of error that is not a syntax problem, and it is the only one with a manual action attached.
JSON-LD vs Microdata, and where to put the script tag
Schema.org can be expressed three ways: JSON-LD in a script tag, Microdata as attributes on your HTML elements, and RDFa. Google recommends JSON-LD and every example in its documentation uses it. The reason is separation — the markup is one block you can generate, template, diff and delete without touching the layout.
Microdata is not wrong and Google still reads it, but it couples your markup to your DOM: moving a div can break the item, and a component library that re-renders your HTML will eventually strip an itemprop. Mixing both on the same page is the worst option, because the two descriptions drift apart and nobody notices.
The script tag can go in the head or the body — Google states both are fine — so put it wherever your template makes it easiest to keep correct. In SvelteKit that is usually inside svelte:head; in a CMS it is often a template field. What matters more is that the values come from the same source as the visible page, so they cannot go stale independently.
How to test it, and why a valid file can still show nothing
There are three tools and they answer different questions. Google's Rich Results Test tells you whether a page is eligible for a specific rich result — it only understands the types Google supports, so anything else comes back as "no items detected", which is not an error. The Schema Markup Validator at validator.schema.org checks Schema.org syntax for every type, including the ones Google ignores. Search Console's Enhancements reports show what Google actually found on your live pages over time, which is the only one of the three that reflects the real index.
This page sits before all three. It checks the markup you are drafting — including on a staging site, a local build or a page that does not exist yet — without a URL, a login or a queue. Use it to get the structure right, then confirm eligibility with the Rich Results Test once the page is live.
Valid markup with no rich result is normal, not a bug. Eligibility is a precondition, not a promise: Google decides per query whether to show the enhanced format, some types are restricted to certain regions or languages, new pages need to be crawled and reprocessed first, and a manual action for spammy structured data suppresses everything site-wide. Check Search Console before you rewrite the markup — if the item is listed as valid there, the markup is not the problem.