Skip to content
← Back to Learn
Structured Data Info

Missing structured data

JSON-LD teaches search engines and LLMs what a page actually is. Article, Product, Organization, BreadcrumbList — these still earn rich results in 2026.

Structured data is the API your HTML exposes to search engines and AI systems. Pages with valid schema.org JSON-LD earn rich SERP treatments, appear more reliably as citations in AI Overviews and ChatGPT answers, and are easier for downstream systems to index correctly.

This guide covers what’s still worth implementing in 2026, what’s been deprecated or de-emphasized, and how to add it without the common over-claiming traps.

Which types actually matter (2026)

Worth implementing:

  • Organization — global, on the homepage. Logo, name, sameAs to social profiles. Used by Google for the knowledge panel and by LLMs as the canonical “who is this brand.”
  • WebSite with SearchAction — global, on the homepage. Enables Google’s sitelinks search box.
  • BreadcrumbList — on every non-root page. Cheap to implement, visible in the SERP.
  • Article / BlogPosting / NewsArticle — on editorial content. Eligibility for Top Stories and rich snippets.
  • Product with offers and aggregateRating — on product pages. Required for product rich results. As of 2024–25, Google de-emphasized reviewless products in rich results.
  • FAQPage — still works, but Google massively reduced rich results for FAQ in mid-2023. Implement only if the FAQ is real and useful, not as snippet bait.
  • HowTo — similarly de-emphasized in 2023. Useful for AI surfaces, less for Google rich results.
  • VideoObject — for any embedded video. Required for video rich results, key signal for video search.

Less worth bothering:

  • Person schema with self-claims — Google ignores aggressive self-authority markup.
  • AggregateRating without a real review source — flagged as spam.
  • Microdata or RDFa — use JSON-LD instead. Cleaner, separable from layout, easier to maintain.

How to detect it

curl -s https://example.com/some/page \
  | grep -oE '<script[^>]*type="application/ld\+json"[^>]*>'

Zero matches = missing. Use Google’s Rich Results Test (search.google.com/test/rich-results) or Schema.org’s validator to verify a present block parses and earns rich-result eligibility.

In Google Search Console, Enhancements lists every detected schema type and any errors. Missing schema doesn’t appear here — only what’s present.

The fix — minimum useful set

Universal — homepage

Add an Organization block to identify the brand:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Acme",
  "url": "https://example.com",
  "logo": "https://example.com/logo.png",
  "sameAs": [
    "https://twitter.com/acme",
    "https://www.linkedin.com/company/acme",
    "https://github.com/acme"
  ]
}
</script>

Pair with a WebSite block if you want the SERP search box:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "url": "https://example.com",
  "potentialAction": {
    "@type": "SearchAction",
    "target": "https://example.com/search?q={search_term_string}",
    "query-input": "required name=search_term_string"
  }
}
</script>

Universal — blog post / article

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "How to write a meta description that survives Google rewrite",
  "image": ["https://example.com/og-image.jpg"],
  "datePublished": "2026-05-01T08:00:00+00:00",
  "dateModified": "2026-05-12T10:15:00+00:00",
  "author": {
    "@type": "Person",
    "name": "Daniel Jacobsen",
    "url": "https://example.com/authors/daniel"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Acme",
    "logo": {
      "@type": "ImageObject",
      "url": "https://example.com/logo.png"
    }
  }
}
</script>

ISO 8601 dates with timezone offsets. Real author with a real url to a real author bio page (Google’s E-E-A-T signal).

Universal — product page

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Widget Pro",
  "image": "https://example.com/widget.jpg",
  "description": "Industrial-grade widget for engineering teams.",
  "sku": "WGT-PRO-001",
  "brand": { "@type": "Brand", "name": "Acme" },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/products/widget-pro",
    "priceCurrency": "USD",
    "price": "99.00",
    "availability": "https://schema.org/InStock"
  }
}
</script>

If you have real third-party reviews, add aggregateRating. Don’t fabricate.

Universal — breadcrumbs

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "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": "How to write a meta description" }
  ]
}
</script>

The last item omits item because it’s the current page.

WordPress (Yoast / Rank Math)

Both plugins emit Organization, WebSite, Article, and BreadcrumbList automatically. Verify what they produce with Rich Results Test — auto-output is usually decent, occasionally has gaps (missing publisher logo, missing dateModified).

Add Product schema via WooCommerce — both plugins integrate. Add custom schema (e.g. HowTo for a tutorial) via the per-post schema editor.

Shopify

Themes ship JSON-LD by default, but quality varies. Open templates/product.liquid and templates/article.liquid, find the application/ld+json block, and validate it against the Rich Results Test.

The most common Shopify schema gap: missing aggregateRating on products because the theme doesn’t pull from a reviews app. Connect Loox, Judge.me, or similar; their snippets typically include the rating field.

Next.js (App Router)

Render as a <script type="application/ld+json"> element directly in the page component:

// app/blog/[slug]/page.tsx
export default async function Page({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  const ld = {
    "@context": "https://schema.org",
    "@type": "Article",
    headline: post.title,
    datePublished: post.publishedAt,
    dateModified: post.updatedAt,
    author: { "@type": "Person", name: post.author.name },
  };
  return (
    <>
      <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />
      <article>{/* ... */}</article>
    </>
  );
}

Render server-side. Don’t inject JSON-LD via client-side JS — many AI crawlers won’t see it.

Pitfalls

Don’t ship JSON-LD that doesn’t match what’s on the page. A Product schema with a price the visible page doesn’t show is a manual-action risk.

Don’t fabricate aggregateRating. Google penalizes review schema with no visible source. Use real reviews from a real source, or omit.

Don’t over-claim Article for non-articles. Marketing landing pages aren’t articles. Use WebPage or no schema at all.

Don’t ship multiple conflicting blocks. Two Organization blocks with different names confuse the parser. One per page per type.

Don’t ship JSON-LD only after JS hydration. Render server-side; many AI crawlers (and Googlebot’s first pass) won’t run JS.

Fix at the edge with Serpwise

The slow path to structured data is “add JSON-LD generation to every CMS template that renders SEO-critical content.” On a multi-stack site, that’s a project.

The fast path is to inject JSON-LD at the edge based on URL patterns and on-page signals: extract the article title, publish date, and author bio from the rendered HTML; generate a valid Article schema; inject it before the response leaves the edge. Apply across thousands of URLs in minutes, audit in one dashboard, deprecate per template as upstream catches up.

See pricing or run a free AI visibility audit.

From diagnosis to deployment

Find the issue. Ship the fix.

Use Learn to understand the problem, then run Serpwise against your own site to see what can be approved and deployed.