On this page 10 sections
- Markup is a claim about the page, not a ranking trick
- The types a small site actually needs
- Person, Organization and sameAs
- Article, BreadcrumbList and WebPage together
- FAQPage only when the questions are visible
- The errors that get markup ignored
- Testing, diffs and not drifting from the HTML
- A starter graph you can adapt
- Key takeaways
- Frequently asked questions
I publish JSON-LD on leej.uk from the same source as the article, and I built validators for it because a graph that drifts from the HTML is worse than a missing graph. The method below is how I keep the two aligned.
Markup is a claim about the page, not a ranking trick
schema.org is a shared vocabulary. JSON-LD is one way to write it down, and it is the format Google recommends in its structured data documentation. The script does not have to be visible to the reader, but the facts in it do. If the JSON says the author is a chartered engineer in Manchester and the page never says so, you have created a second, quieter page that only machines are invited to trust.
Google’s structured data policies are the rules to read before you chase a rich result. They change in detail, so I will not restate them as a permanent checklist. The durable bit is: mark up content that is on the page, do not mark up content that is misleading, and do not use a type you cannot stand behind.
Rich results — FAQ foldouts, article features, sitelinks search boxes — are optional presentations. Valid markup makes a page eligible for some of them. It does not entitle you to any of them, and eligibility can change. I treat JSON-LD the way I treat a privacy manifest: a precise declaration of what is actually there, not a brochure for a reviewer or a crawler.
The types a small site actually needs
A small business or personal site rarely needs a zoo of types. A useful starter set is:
WebSiteon the home page, with the site name and the canonical URL. ASearchActiononly if you actually have a working on-site search, not as decoration.OrganizationorPerson, depending on whether the site represents a company or an identifiable individual. This is the entity the rest of the graph can point at.WebPage(or a more specific subtype) for ordinary pages, withname,url, andisPartOfthe site.ArticleorTechArticlefor long-form writing, withheadline,datePublished,dateModifiedif you have it, andauthor.BreadcrumbListwhen the visible breadcrumb is real.FAQPageonly on pages that visibly ask and answer those questions, as a later section explains.
Add other types when the page is genuinely that thing: SoftwareApplication for a shipped app, ContactPage for a contact page, Offer only if you are displaying a price you would honour. Do not add Product, Review or AggregateRating because a tutorial mentioned a rich result. Invented reviews are one of the fastest ways to have markup ignored, or worse.
The Schema Generator can draft these types. The Schema Entity Graph is useful when you want to see how the nodes join. Neither tool should invent a type the page does not support.
Person, Organization and sameAs
Search engines and assistants need to know who is speaking, and which official profiles belong to that entity. That is the job of a stable Person or Organization node, plus sameAs links to profiles you actually control.
A compact, imaginary example for a sole trader might look like this:
{
"@context": "https://schema.org",
"@type": "Person",
"@id": "https://example.com/#person",
"name": "Alex Hart",
"url": "https://example.com/",
"email": "desk@example.com",
"sameAs": [
"https://github.com/example",
"https://www.linkedin.com/in/example"
]
}Choices that matter:
- Give the entity an
@idyou can reuse from articles and the home page, so you are not inventing a new “Alex Hart” on every URL. sameAsis for official identities, not for every mention or every directory scrape. A GitHub, a company number page, a LinkedIn profile, an App Store artist page: yes, if they are yours. A random “best of” list: no.- Match the visible site. If the site is clearly a person trading under their own name,
Personis more honest than a made-upOrganization. If there is a registered company, you can have both, linked withfounderorworksFor, but only when that relationship is real. - Do not fill empty fields with guesses. A
telephoneoraddressthat is not on the site should not appear in the graph.
The Entity Home and sameAs Builder is a way to assemble that node. I use the same “only list what exists” rule that I use in the case study on small, focused Apple apps.
Article, BreadcrumbList and WebPage together
A long article is easier to understand when the graph says, in one go: this is a page, it is an article, it sits in a breadcrumb, and it was written by that person. JSON-LD can express that as a single @graph, or as one node with nested properties. I prefer a graph with stable @ids, so the article can point at the person and the breadcrumb without repeating their details.
A sketch, trimmed to the ideas that matter:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "TechArticle",
"@id": "https://example.com/articles/example#article",
"headline": "How to keep an XML sitemap accurate",
"datePublished": "2026-11-10",
"author": { "@id": "https://example.com/#person" },
"mainEntityOfPage": { "@id": "https://example.com/articles/example#webpage" }
},
{
"@type": "WebPage",
"@id": "https://example.com/articles/example#webpage",
"url": "https://example.com/articles/example",
"isPartOf": { "@id": "https://example.com/#website" },
"breadcrumb": { "@id": "https://example.com/articles/example#breadcrumb" }
},
{
"@type": "BreadcrumbList",
"@id": "https://example.com/articles/example#breadcrumb",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
{ "@type": "ListItem", "position": 2, "name": "Articles", "item": "https://example.com/articles" },
{ "@type": "ListItem", "position": 3, "name": "How to keep an XML sitemap accurate" }
]
}
]
}The last breadcrumb item is the current page; it does not have to repeat the URL as item, but the visible trail and the list must agree. Dates must match what you would defend on the page. A headline should be the actual title, not a more “clickable” variant you would not show in the H1.
You do not have to mark every page as an Article. A contact page is not an article. A tool page may be a WebPage and, if it is genuinely a piece of software you offer, something more specific, but it should not pretend to be a news story.
FAQPage only when the questions are visible
FAQPage is the type teams add too quickly. It is appropriate when the page visibly contains questions and answers, in a form a person can read without running a special script, and when those questions are the main or a substantial part of the page, or a clearly marked section of it.
It is not appropriate when:
- The questions exist only in the JSON-LD, or only in a collapsed component that never appears in the first HTML response.
- You have generated twenty near-duplicate questions to capture variants.
- Every page on the site has the same generic FAQ nailed into the footer.
- The “answers” are sales copy, or they contradict the body.
Google has narrowed how FAQ rich results are shown over time, and that policy can change again. Even if a rich result is not on offer for your site, honest visible FAQs can still help a reader and an assistant. Invisible FAQs help nobody and can violate policy.
On this site, article FAQs are written in the page, then turned into both an accordion and, only then, FAQPage markup. The answers are the same words. If I would not show the question, I do not mark it up.
The errors that get markup ignored
The usual failures, in the order I look for them:
- The JSON is invalid. A trailing comma, an unescaped quote, or a script tag that broke the document. The page may still render; the graph will not parse.
- Required properties are missing for the type you chose, or you used a type that does not mean what you think it means.
- The facts do not match the page. A different title, a different author, a price that is not shown, a breadcrumb that does not exist, an
FAQPagewith no visible questions. - Invented reviews and ratings. Do not mark up testimonials you do not display, and do not average them into an
AggregateRatingyou would not print. - Stale dates or leftover entities after a rename, a new author, or a retired product.
- Hidden or cloaked content, marked up but not available to an ordinary visitor.
- Conflicts between two graphs on the same page, or between JSON-LD and microdata you forgot was still in the template.
When markup is “valid but unused”, it often still has one of those problems, or it is simply not eligible for a rich result. Validity is a floor, not a promise. The Schema and Rich Result Validator will catch many technical issues; it will not tell you whether a sentence is true.
Testing, diffs and not drifting from the HTML
Generate the JSON-LD from the same fields that generate the page: title, dates, author, breadcrumb, visible FAQ. If a person edits the markdown and the graph is hand-copied, the graph will drift. I treat a drift the way I would treat a mismatch in what an iOS app really costs: a number that appears in two places must have one source.
A practical test pass:
- View the page source and confirm the script is present in the first response, not only after a client render.
- Parse the JSON. Fix syntax before you argue about types.
- Validate with a schema tester, and with Google’s own rich results test when you are chasing a specific feature, remembering that tool output can change.
- Diff the graph against the live HTML. The Structured Data Diff is built for that comparison. A property that has no counterpart on the page is a bug.
- Re-run the check when the title, the FAQ or the author line changes, in the same release.
For a short note on giving assistants a map of the site itself, that is llms.txt, not more schema. The two can coexist; they should not contradict each other about who you are.
A starter graph you can adapt
For a small UK studio site, I would ship, at minimum:
- On every page: a
WebSitenode with a stable@id, plusWebPageandBreadcrumbListthat match the visible chrome. - On the home page and in the footer of the graph: one
PersonorOrganizationwithsameAsand a contact method that already appears on the site. - On articles:
ArticleorTechArticlepointing at that person, with real dates. - On a page that truly has a FAQ section:
FAQPagewhose questions and answers are the visible ones.
Then stop. Do not add a LocalBusiness opening-hours block if you do not have a premises and hours. Do not add a Product for “web design” unless you are selling a product with a price. The writing guide for AI answers applies to the graph as much as to the prose: say what is true, and leave a clean silence where you do not have a fact.
A launch is a good moment to validate this set once, as part of a technical SEO launch checklist, and then to keep the generator honest as pages change.
Key takeaways
- JSON-LD is a claim about the visible page. It can help search and AI when it is valid and truthful; it is not a ranking switch.
- A small site usually needs a short graph: site, person or organisation, page, article, breadcrumbs, and FAQ only when the questions are on the page.
- Use stable
@ids andsameAslinks to official profiles you control. Do not invent contact details, reviews or types the page cannot support. - Generate the markup from the same source as the HTML, then validate and diff it whenever the page changes.
- “Valid but unused” usually means a policy or eligibility issue, a mismatch with the page, or a rich result you were never entitled to.
If you want a second pair of eyes on a graph that is valid and still feels untrustworthy, tell me about it.
Frequently asked questions
What JSON-LD types does a small business website need?
Usually WebSite, WebPage, a Person or Organization, BreadcrumbList, and Article on the writing. Add FAQPage, SoftwareApplication or commercial types only when the page is genuinely that thing and the facts are visible. A short, accurate graph is more useful than a long one with empty fields.
Should FAQ schema be on every page?
No. Use FAQPage only where the questions and answers are visible on that page. Do not hide them in the JSON alone, and do not repeat a generic footer FAQ as schema on every URL. Policies for FAQ rich results have changed over time, but the honesty rule does not.
What is an entity graph in schema.org?
It is a set of nodes with stable identities — you, the organisation, the site, a particular article — linked to each other with properties such as author, isPartOf and sameAs. The point is to say “this article was written by this person, who is the same as these official profiles”, not to add more keywords.
How should Article and BreadcrumbList be combined?
Put them in one JSON-LD graph and give each an @id. The article can point at the page, the page at the breadcrumb, and the breadcrumb can list the visible trail, with positions that match what a person sees. The headline and the last breadcrumb name should agree with the H1.
Why is my structured data valid but unused?
Validity only means the JSON parses and the types look well formed. The markup may still disagree with the page, use a type that is not eligible for a rich result, or fall under a policy restriction. Google also does not have to show a rich result for eligible pages. Check a diff against the HTML, and read the current documentation for the feature you were expecting.
Written by Lee Johnson. Published 10 November 2026.