Structured Data

Making your content explicitly machine-readable with Schema.org markup

Structured data is explicit metadata that tells machines exactly what your content represents. While semantic HTML and ARIA help, they rely on agents inferringmeaning from structure. Structured data eliminates ambiguity by providing explicit type definitions and relationships using standardized vocabularies like Schema.org.

Think of it as the difference between showing someone a picture of an apple and telling them "This is an apple, it's a Granny Smith variety, it costs $1.99, and it's in stock." Both convey information, but the explicit version is unambiguous and actionable.

Why Structured Data Matters for BiModal Design

For Agents

  • Eliminates guesswork—agents know exactly what content represents
  • Enables direct data extraction without parsing HTML
  • Provides pricing, availability, and transaction data
  • Supports complex relationships (product → brand → reviews)

For Humans (via Search)

  • Rich snippets in Google search results
  • Knowledge graph integration
  • Better click-through rates (CTR)
  • Voice assistant compatibility

Two Formats: JSON-LD vs Microdata

Schema.org markup can be implemented in two main formats:

JSON-LD (Recommended)

JavaScript Object Notation for Linked Data. A separate script tag containing structured data in JSON format.

Advantages:

  • ✓ Clean separation from HTML
  • ✓ Easier to maintain and generate
  • ✓ Can be added dynamically
  • ✓ Preferred by Google
  • ✓ No attribute clutter in HTML

Microdata

HTML attributes added directly to existing elements to annotate content.

Advantages:

  • → Content and markup stay together
  • → Visible in HTML source
  • → Some prefer inline approach

Disadvantages:

  • ✗ Clutters HTML with attributes
  • ✗ Harder to maintain
  • ✗ More verbose

💡 BiModal Recommendation

Use JSON-LD for most scenarios. It keeps your HTML clean, is easier to generate server-side, and is preferred by major search engines. Use Microdata only if you have a specific requirement for inline markup.

Essential Schema.org Types

Product

Describes a product for sale. Essential for e-commerce sites. Includes name, price, availability, reviews, and more.

JSON-LD ExampleRecommended
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Headphones",
  "description": "Premium noise-canceling wireless headphones",
  "image": "https://example.com/headphones.jpg",
  "brand": {
    "@type": "Brand",
    "name": "AudioTech"
  },
  "offers": {
    "@type": "Offer",
    "price": "299.99",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://example.com/product/headphones"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "reviewCount": "142"
  }
}
</script>

Key Properties:

name - Product name
description - Product description
image - Product image URL
brand - Brand information
offers - Price and availability
aggregateRating - Review ratings
sku - Stock keeping unit
gtin - Global trade item number

Article / BlogPosting

Describes written content like blog posts, news articles, or documentation. Helps search engines display rich article snippets.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Getting Started with BiModal Design",
  "description": "Learn how to build websites that work for humans and agents",
  "image": "https://example.com/article-image.jpg",
  "author": {
    "@type": "Person",
    "name": "Jane Developer",
    "url": "https://example.com/author/jane"
  },
  "publisher": {
    "@type": "Organization",
    "name": "BiModal Design",
    "logo": {
      "@type": "ImageObject",
      "url": "https://example.com/logo.png"
    }
  },
  "datePublished": "2025-01-15T08:00:00+00:00",
  "dateModified": "2025-01-20T10:30:00+00:00",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://example.com/article/bimodal-intro"
  }
}
</script>

Organization

Describes a company, nonprofit, or institution. Should be on your homepage or about page.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "BiModal Design Co",
  "url": "https://bimodal.design",
  "logo": "https://bimodal.design/logo.png",
  "description": "Web design framework for humans and agents",
  "contactPoint": {
    "@type": "ContactPoint",
    "telephone": "+1-555-0123",
    "contactType": "customer service",
    "email": "hello@bimodal.design"
  },
  "sameAs": [
    "https://twitter.com/bimodaldesign",
    "https://github.com/bimodal-design",
    "https://linkedin.com/company/bimodal-design"
  ]
}
</script>

Describes the navigation path to the current page. Helps agents understand site hierarchy.

<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": "Products",
      "item": "https://example.com/products"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Wireless Headphones",
      "item": "https://example.com/products/headphones"
    }
  ]
}
</script>

FAQPage

Structures frequently asked questions. Can appear as rich snippets in search results.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is BiModal Design?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "BiModal Design is a web development approach that creates interfaces accessible to both human users and AI agents."
      }
    },
    {
      "@type": "Question",
      "name": "Why do AI agents need special consideration?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Most AI agents cannot execute JavaScript, so content rendered client-side is invisible to them."
      }
    }
  ]
}
</script>

Microdata Format (Alternative)

If you prefer inline markup, here's the same Product example using Microdata:

Microdata ExampleAlternative
<article itemScope itemType="https://schema.org/Product">
  <h1 itemProp="name">Wireless Headphones</h1>

  <img src="headphones.jpg" alt="Wireless Headphones" itemProp="image" />

  <p itemProp="description">
    Premium noise-canceling wireless headphones
  </p>

  <div itemProp="brand" itemScope itemType="https://schema.org/Brand">
    <span itemProp="name">AudioTech</span>
  </div>

  <div itemProp="offers" itemScope itemType="https://schema.org/Offer">
    <span itemProp="price">299.99</span>
    <meta itemProp="priceCurrency" content="USD" />
    <link itemProp="availability" href="https://schema.org/InStock" />
  </div>

  <div itemProp="aggregateRating" itemScope itemType="https://schema.org/AggregateRating">
    <span itemProp="ratingValue">4.5</span> out of 5
    based on <span itemProp="reviewCount">142</span> reviews
  </div>
</article>

⚠ Microdata Considerations

While Microdata keeps markup and content together, it makes HTML harder to read and maintain. For complex schemas with nested objects, JSON-LD is significantly cleaner.

Framework Implementation

Next.js / React

// app/products/[id]/page.tsx
export default async function ProductPage({ params }) {
  const product = await getProduct(params.id);

  const schema = {
    "@context": "https://schema.org",
    "@type": "Product",
    "name": product.name,
    "description": product.description,
    "image": product.image,
    "offers": {
      "@type": "Offer",
      "price": product.price,
      "priceCurrency": "USD",
      "availability": product.inStock
        ? "https://schema.org/InStock"
        : "https://schema.org/OutOfStock"
    }
  };

  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
      />

      <article>
        <h1>{product.name}</h1>
        <p>{product.description}</p>
        <p>${product.price}</p>
      </article>
    </>
  );
}

Vue / Nuxt

<!-- pages/products/[id].vue -->
<script setup>
const route = useRoute();
const product = await getProduct(route.params.id);

const schema = {
  "@context": "https://schema.org",
  "@type": "Product",
  "name": product.name,
  "description": product.description,
  "image": product.image,
  "offers": {
    "@type": "Offer",
    "price": product.price,
    "priceCurrency": "USD",
    "availability": product.inStock
      ? "https://schema.org/InStock"
      : "https://schema.org/OutOfStock"
  }
};

useHead({
  script: [
    {
      type: 'application/ld+json',
      children: JSON.stringify(schema)
    }
  ]
});
</script>

<template>
  <article>
    <h1>{{ product.name }}</h1>
    <p>{{ product.description }}</p>
    <p>${{ product.price }}</p>
  </article>
</template>

Testing & Validation

Google Rich Results Test

Tests if your structured data is eligible for Google rich results. Shows preview of how your page might appear in search.

Test with Google →

Schema Markup Validator

Official Schema.org validator. Checks for syntax errors and validates against the Schema.org vocabulary.

Validate Schema.org →

Structured Data Linter

Quick validation tool for JSON-LD. Paste your markup and get immediate feedback on errors.

JSON-LD Playground →

Browser DevTools

Inspect the page source to verify your JSON-LD script tags are rendering correctly in the HTML.

View → Developer → View Source

Common Implementation Patterns

E-commerce Product Page

Combine Product + Organization + BreadcrumbList for maximum context:

<script type="application/ld+json">
[
  {
    "@context": "https://schema.org",
    "@type": "Product",
    "name": "Product Name",
    "offers": { ... }
  },
  {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [ ... ]
  }
]
</script>

Blog Post with Author

Include Article + Person (author) + Organization (publisher):

{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Article Title",
  "author": {
    "@type": "Person",
    "name": "Author Name"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Site Name"
  }
}

Local Business

Include address, hours, and geographic coordinates:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Coffee Shop",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "San Francisco",
    "addressRegion": "CA",
    "postalCode": "94102"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": "37.7749",
    "longitude": "-122.4194"
  },
  "openingHours": "Mo-Fr 07:00-19:00"
}

Best Practices

✓ DO

  • • Use JSON-LD unless you have a specific reason not to
  • • Place JSON-LD in the <head> or at the end of <body>
  • • Include all required properties for your chosen type
  • • Use absolute URLs for images and pages
  • • Test with Google Rich Results and Schema.org validator
  • • Keep structured data in sync with visible content
  • • Use specific Schema types (BlogPosting vs Article)

✗ DON'T

  • • Include content in structured data that's not visible on the page
  • • Use structured data to manipulate search rankings (spam)
  • • Mark up content that's not the main focus of the page
  • • Copy/paste examples without customizing for your content
  • • Include invalid or placeholder data
  • • Mix JSON-LD and Microdata on the same element
  • • Forget to escape HTML entities in JSON strings

💡 Multiple Schema Types on One Page

You can include multiple JSON-LD scripts on a single page, or combine them in an array:

<!-- Option 1: Multiple script tags -->
<script type="application/ld+json">
{ "@type": "Product", ... }
</script>
<script type="application/ld+json">
{ "@type": "BreadcrumbList", ... }
</script>

<!-- Option 2: Array in single script -->
<script type="application/ld+json">
[
  { "@type": "Product", ... },
  { "@type": "BreadcrumbList", ... }
]
</script>

Next Steps

With semantic HTML, ARIA, and structured data in place, learn about specialized attributes that help agents perform tasks on your site.

Continue to Agent Attributes →