The mental model

A web page is a document. A search engine crawler looks at it and tries to guess: is this an article? A product? A person's homepage? A recipe? That guess drives which "rich" treatments are available in the search results.

Schema.org is the shared vocabulary you use to stop making the crawler guess. You declare, in machine-readable JSON, exactly what each thing on the page is and how the things relate. Crawlers don't have to infer — they know.

Structured data is annotations for machines. The goal isn't to stuff in every schema type available; it's to declare the handful of things that are actually true about each page, and then wire them together cleanly.

What you get out of it

Why JSON-LD beats microdata

Schema.org markup can be delivered three ways: JSON-LD, microdata, or RDFa. Google officially supports all three; in practice, use JSON-LD.

All examples below are JSON-LD.

Organization schema

Organization schema is the "who runs this site" declaration. For a company, agency, or business, this is almost always the right root entity.

Place this in <head> on your homepage, and reference it from every other page via @id.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://example.com/#organization",
  "name": "Example Co.",
  "url": "https://example.com/",
  "logo": {
    "@type": "ImageObject",
    "url": "https://example.com/logo.png",
    "width": 512,
    "height": 512
  },
  "sameAs": [
    "https://www.linkedin.com/company/example",
    "https://twitter.com/example",
    "https://www.youtube.com/@example"
  ],
  "contactPoint": [{
    "@type": "ContactPoint",
    "contactType": "customer support",
    "email": "hello@example.com",
    "areaServed": "AU",
    "availableLanguage": ["English"]
  }],
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Sydney",
    "addressRegion": "NSW",
    "addressCountry": "AU"
  }
}
</script>

The sameAs array is one of the highest-leverage properties in all of schema. It's how you tell Google "these other profiles on the internet are this same entity." That's the mechanism behind knowledge panels appearing, and it's how Google fuses your reputation across platforms.

Person schema (for solo sites)

If the site is a personal brand or solo operator, use Person instead of (or alongside) Organization. For this site, Person is the root entity — there's no company behind it, just me.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Person",
  "@id": "https://anthonyligyat.com/#person",
  "name": "Anthony Ligyat",
  "jobTitle": "Growth Marketing Consultant",
  "url": "https://anthonyligyat.com/",
  "image": "https://anthonyligyat.com/anthony.jpg",
  "description": "Sydney-based growth marketing consultant. Nine months in-house at Excelerate Consulting; now building the international brand for Yuan Packaging.",
  "sameAs": [
    "https://www.linkedin.com/in/anthonyligyat/"
  ],
  "alumniOf": [
    { "@type": "CollegeOrUniversity", "name": "UNSW Sydney" }
  ],
  "knowsAbout": [
    "AI marketing automation",
    "Ebook lead funnels",
    "International SEO",
    "GA4"
  ],
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Sydney",
    "addressRegion": "NSW",
    "addressCountry": "AU"
  }
}
</script>

knowsAbout lets you declare topical expertise without stuffing your bio. alumniOf adds a formal-credential signal. sameAs does the reputation-fusing work described above.

WebSite schema

WebSite schema declares the site itself as an entity, separate from its owner. It also lets you wire in a SearchAction so Google can show a sitelinks search box under your homepage in results.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "@id": "https://example.com/#website",
  "url": "https://example.com/",
  "name": "Example",
  "publisher": { "@id": "https://example.com/#organization" },
  "inLanguage": "en-AU",
  "potentialAction": {
    "@type": "SearchAction",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://example.com/search?q={search_term_string}"
    },
    "query-input": "required name=search_term_string"
  }
}
</script>

Skip the SearchAction if you don't have an on-site search. Keep the rest.

Article schema

On any page that's a proper article (blog post, guide, long-form), add Article schema. This is the main piece that unlocks Article-style rich snippets — bylines in SERPs, "top stories" eligibility, AI-search attribution.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "@id": "https://example.com/blog/my-post.html#article",
  "mainEntityOfPage": "https://example.com/blog/my-post.html",
  "headline": "My post's headline, exactly as shown",
  "description": "One-sentence description, ≤160 chars.",
  "image": "https://example.com/my-post-hero.png",
  "author": {
    "@type": "Person",
    "@id": "https://example.com/#person",
    "name": "Jane Doe",
    "url": "https://example.com/about.html"
  },
  "publisher": { "@id": "https://example.com/#organization" },
  "datePublished": "2026-04-24",
  "dateModified": "2026-05-21",
  "articleSection": "SEO",
  "inLanguage": "en-AU",
  "keywords": "Schema.org, JSON-LD, Rich Snippets"
}
</script>

Two things matter most here: (1) author is an object with a real Person, ideally referencing the same @id as the one on your About / homepage; (2) datePublished and dateModified are real and match what's visible on the page.

BreadcrumbList is the one that earns you that clean Home › Category › Article trail in the search result instead of a raw URL. Quick win on any multi-page site.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "@id": "https://example.com/blog/my-post.html#breadcrumb",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Home",
      "item": "https://example.com/" },
    { "@type": "ListItem", "position": 2, "name": "Blog",
      "item": "https://example.com/blog/" },
    { "@type": "ListItem", "position": 3, "name": "My post",
      "item": "https://example.com/blog/my-post.html" }
  ]
}
</script>

Keep the breadcrumb structure consistent with what's actually shown on the page and in the URL. Don't invent a taxonomy that doesn't exist.

Tying it all together with @graph

On your homepage, the cleanest pattern is a single @graph block containing the Organization (or Person), the WebSite, and the WebPage, with @id references wiring them together.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Person",
      "@id": "https://anthonyligyat.com/#person",
      "name": "Anthony Ligyat",
      "url": "https://anthonyligyat.com/",
      "sameAs": ["https://www.linkedin.com/in/anthonyligyat/"]
    },
    {
      "@type": "WebSite",
      "@id": "https://anthonyligyat.com/#website",
      "url": "https://anthonyligyat.com/",
      "name": "Anthony Ligyat",
      "publisher": { "@id": "https://anthonyligyat.com/#person" },
      "inLanguage": "en-AU"
    },
    {
      "@type": "WebPage",
      "@id": "https://anthonyligyat.com/#home",
      "url": "https://anthonyligyat.com/",
      "name": "Anthony Ligyat — Marketing, measured.",
      "isPartOf": { "@id": "https://anthonyligyat.com/#website" },
      "about": { "@id": "https://anthonyligyat.com/#person" }
    }
  ]
}
</script>

The @ids aren't URLs to fetch — they're stable identifiers. Using the canonical URL plus a fragment (#person, #website) is the convention. It makes the graph easy to debug and easy to extend.

How to validate

Before you ship markup, run it through at least one of these:

The Rich Results Test will also show you the rendered snippet preview — useful for checking that your headline, image, and byline look right before you commit.

Common mistakes

Marking up things that aren't on the page. The structured data has to match what users actually see. FAQ schema without an actual FAQ on the page will get your site a manual action, not more traffic.

Inflating dates. Changing dateModified every day without real content changes is a tell Google catches quickly, and it can suppress freshness signals entirely.

Fake reviews. Self-serving AggregateRating markup gets penalised. Use genuine reviews from a proper review platform.

Orphaned @ids. If your Article references an author @id that doesn't exist anywhere else on your site, the wiring is broken. Keep the Person or Organization definition consistent across pages.

Stuffing types. A single entity declared as "@type": ["Organization", "Person", "LocalBusiness", "Corporation"] confuses crawlers and adds nothing.

Structured data rewards precision, not volume. Declare the small number of things that are actually true about your site, wire them together with consistent @ids, and let the rich snippets follow.