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.
<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 namedescription - Product descriptionimage - Product image URLbrand - Brand informationoffers - Price and availabilityaggregateRating - Review ratingssku - Stock keeping unitgtin - Global trade item numberArticle / 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>BreadcrumbList
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:
<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 SourceCommon 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 →