Home Journal Technical SEO

Technical SEO

Schema markup that actually does something

Most structured data on the web is decorative — technically valid, functionally pointless. Four types are worth the effort. Here they are.

Schema.org structured data is a vocabulary for stating facts about a page in a format machines read without interpretation. Done well, it makes you eligible for rich results in Google and makes your facts safe for an AI assistant to repeat. Done the way most sites do it, it does nothing at all.

The failure mode is almost always the same: a plugin injects a generic WebPage block on every URL, it validates cleanly, everyone feels productive, and nothing changes — because that block asserts nothing a search engine didn't already know.

Structured data earns its keep when it says something specific and non-obvious. Here are the four types that reliably do.

1. Organization or LocalBusiness

This is the foundation, and it belongs on your homepage — once, sitewide.

It's how you declare the entity behind the website: name, contact details, service area, what you do, and the other places you exist online. Search engines and AI systems both use it to connect your site to a known thing in the world rather than treating it as an anonymous collection of pages.

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://example.com/#business",
  "name": "Example Studio",
  "url": "https://example.com/",
  "email": "hello@example.com",
  "telephone": "+1-555-0100",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "12 Example Ave",
    "addressLocality": "Portland",
    "addressRegion": "OR",
    "postalCode": "97201",
    "addressCountry": "US"
  },
  "sameAs": [
    "https://www.instagram.com/examplestudio",
    "https://www.linkedin.com/company/examplestudio"
  ]
}

Two details people skip that matter more than they look:

  • @id — a stable identifier you can reference from every other block on the site. This is what turns scattered markup into one connected graph.
  • sameAs — links to your profiles elsewhere. It's the closest thing you have to saying "and this is the same business as that one," which is how entity confidence gets built.
Use LocalBusiness only if you're actually local If you don't serve customers at a physical address, use Organization or a specific subtype like ProfessionalService. Claiming a storefront you don't have is the kind of mismatch that gets markup ignored.

2. FAQPage

The single highest-return markup for AEO, and it costs almost nothing.

FAQPage takes questions and answers you've already written and hands them over pre-parsed. There's no ambiguity for a model to resolve — this text is a question, that text is its answer, done.

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [{
    "@type": "Question",
    "name": "How long does a website build take?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "A typical five to eight page marketing site takes
               two to four weeks from kickoff to launch."
    }
  }]
}

Three rules that keep it working:

  • The Q&A must be visible on the page. Markup describing content a user can't see is a violation, not a shortcut.
  • Answer completely inside the text field. "It depends — read on below" is worthless when extracted.
  • Write real questions. Phrase them the way a customer would say them out loud, not the way a keyword tool spells them.

Google has narrowed which sites get FAQ rich results in regular search — but the markup is still read, still used for AI Overviews, and still parsed by other answer engines. Its value shifted from decoration to comprehension. That's an upgrade.

3. Article or BlogPosting

For anything dated and authored. It establishes three things a model cares about a great deal: who wrote this, when, and what it's about.

The author field is the one worth fussing over. Point it at a Person with its own @id, and give that person a real page with real credentials. This is how a byline stops being a text string and starts being an entity with a reputation attached — which is most of what E-E-A-T means in practice.

{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Schema markup that actually does something",
  "datePublished": "2026-06-23",
  "dateModified": "2026-06-23",
  "author": { "@id": "https://example.com/about#jane" },
  "publisher": { "@id": "https://example.com/#business" },
  "mainEntityOfPage": "https://example.com/blog/schema.html"
}

Keep dateModified honest. Bumping it on unchanged pages to look fresh is a well-known trick, it's detectable, and it erodes trust in every date you publish.

4. Service or Product

Whichever fits what you sell. Both exist to answer the question a search engine can't reliably infer from prose: what does this business actually offer, and on what terms?

For services, Service with a nested Offer lets you state the thing and its price separately. For physical goods, Product with Offer, availability and real AggregateRating is what drives the rich results that visibly change click-through rates in shopping queries.

One warning worth taking seriously: only mark up reviews and ratings that genuinely exist and are genuinely visible on that page. Fabricated AggregateRating is among the most consistently penalized structured data mistakes there is, and the penalty tends to apply sitewide.

How do you connect it all together?

This is the step that separates markup that works from markup that merely validates.

Use @graph to put several blocks in one script tag, give each an @id, and reference those ids instead of repeating yourself:

{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "Organization", "@id": "https://example.com/#business", "name": "Example Studio" },
    { "@type": "Person",       "@id": "https://example.com/about#jane", "name": "Jane Doe",
      "worksFor": { "@id": "https://example.com/#business" } },
    { "@type": "BlogPosting",  "headline": "…",
      "author":    { "@id": "https://example.com/about#jane" },
      "publisher": { "@id": "https://example.com/#business" } }
  ]
}

Now a machine reading any single page can follow the references: this article was written by this person, who works for this organization, which is the publisher. That's a knowledge graph — small, but real, and it's yours.

How do you know it's actually working?

Validation and monitoring are two different jobs. Do both.

  • Rich Results Test — tells you whether Google considers the page eligible for a specific rich result. Eligibility is not a guarantee of display.
  • Schema Markup Validator (validator.schema.org) — checks general Schema.org validity, including types Google doesn't render. Use this when your markup is for comprehension rather than rich results.
  • Search Console → Enhancements — the only one that reports on pages already indexed, at scale, over time. This is where you catch the template change that quietly broke markup on four hundred URLs.

The short version

Skip the generic blocks. Put Organization or LocalBusiness on the homepage with a stable @id and honest sameAs links. Add FAQPage anywhere you answer real questions. Use Article with a properly referenced author on anything you publish. Describe what you sell with Service or Product. Wire it together with @graph and @id.

Five things. An afternoon's work on most sites, and more useful than every plugin-generated block you'll ever ship.

Not sure what your site is currently telling machines?

An audit covers exactly this — what's there, what's broken, and what's missing.

See the audit