google-structured-data

Google Search structured data implementation - Schema.org markup for rich results, JSON-LD templates, JavaScript generation, and SEO best practices

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "google-structured-data" with this command: npx skills add enuno/claude-command-and-control/enuno-claude-command-and-control-google-structured-data

Google Structured Data Skill

Implement Schema.org structured data markup for Google Search rich results. This skill provides JSON-LD templates, required/recommended properties, and best practices for all major structured data types.

When to Use This Skill

Trigger this skill when:

  • Adding structured data to web pages for SEO
  • Implementing JSON-LD markup for rich results
  • Creating Schema.org markup for articles, products, events, FAQs, recipes, videos, or local businesses
  • Generating structured data dynamically with JavaScript or Google Tag Manager
  • Debugging structured data issues
  • Optimizing search appearance in Google Search, News, or Discover

Quick Reference

Supported Formats

  • JSON-LD (Recommended) - Embedded in <script type="application/ld+json">
  • Microdata - Inline HTML attributes
  • RDFa - Semantic HTML attributes

Core Principles

  1. Mark up visible content only - Don't mark up hidden content
  2. Be accurate - Markup must represent actual page content
  3. Be specific - Use the most specific Schema.org type
  4. Include all required properties - Each type has mandatory fields
  5. Test before deploying - Use Rich Results Test tool

Common Structured Data Types

1. Article (NewsArticle, BlogPosting)

Use for: News articles, blog posts, sports articles

Required: None (all recommended)

Recommended Properties:

  • headline - Article title (keep concise)
  • image - Representative images (16x9, 4x3, 1x1 ratios; min 50K pixels)
  • datePublished - ISO 8601 with timezone
  • dateModified - Last modification date
  • author - Person or Organization with name and URL
{
  "@context": "https://schema.org",
  "@type": "NewsArticle",
  "headline": "Article Title Here",
  "image": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg"
  ],
  "datePublished": "2024-01-05T08:00:00+08:00",
  "dateModified": "2024-02-05T09:20:00+08:00",
  "author": [{
    "@type": "Person",
    "name": "Jane Doe",
    "url": "https://example.com/profile/janedoe123"
  }]
}

2. Product

Use for: E-commerce product pages, product reviews

Required Properties:

  • name - Product name

Recommended Properties:

  • image - Product images
  • description - Product description
  • brand - Brand name
  • offers - Price, availability, currency
  • aggregateRating - Average rating
  • review - Individual reviews
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Executive Anvil",
  "image": "https://example.com/anvil.jpg",
  "description": "Sleek and deadly executive anvil.",
  "brand": {
    "@type": "Brand",
    "name": "ACME"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/anvil",
    "priceCurrency": "USD",
    "price": 119.99,
    "availability": "https://schema.org/InStock",
    "priceValidUntil": "2025-12-31"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.4,
    "reviewCount": 89
  }
}

3. LocalBusiness

Use for: Physical business locations, restaurants, stores

Required Properties:

  • name - Business name
  • address - Full postal address

Recommended Properties:

  • telephone - With country code
  • openingHoursSpecification - Business hours
  • geo - Latitude/longitude (min 5 decimal places)
  • url - Location-specific URL
  • priceRange - "$" to "$$$$" or price range
  • servesCuisine - For restaurants
  • menu - Menu URL for food establishments
{
  "@context": "https://schema.org",
  "@type": "Restaurant",
  "name": "Dave's Steak House",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "148 W 51st St",
    "addressLocality": "New York",
    "addressRegion": "NY",
    "postalCode": "10019",
    "addressCountry": "US"
  },
  "telephone": "+12122459600",
  "url": "https://www.example.com/restaurant-locations/manhattan",
  "servesCuisine": "American",
  "priceRange": "$$$",
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 40.761293,
    "longitude": -73.982294
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "11:30",
      "closes": "22:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Saturday"],
      "opens": "16:00",
      "closes": "23:00"
    }
  ],
  "menu": "https://www.example.com/menu"
}

4. FAQPage

Use for: FAQ pages on authoritative sites (government, health)

Required Properties:

  • mainEntity - Array of Question objects

Question Required Properties:

  • name - Full question text
  • acceptedAnswer - Answer object with text property
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is the return policy?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "<p>You can return items within 30 days of purchase.</p>"
      }
    },
    {
      "@type": "Question",
      "name": "How do I track my order?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "<p>Use the tracking link in your confirmation email.</p>"
      }
    }
  ]
}

Allowed HTML in answers: <h1>-<h6>, <br>, <ol>, <ul>, <li>, <a>, <p>, <div>, <b>, <strong>, <i>, <em>


5. Event

Use for: Concerts, conferences, festivals, sports events

Required Properties:

  • name - Event title (no venue names or promotions)
  • startDate - ISO 8601 with timezone offset
  • location - Place with name and full address

Recommended Properties:

  • description - Event details
  • endDate - When event concludes
  • eventStatus - EventScheduled, EventCancelled, EventPostponed, EventRescheduled
  • image - High-res images (1920px width, 16x9/4x3/1x1)
  • offers - Ticket info with price, currency, availability, URL
  • organizer - Hosting organization
  • performer - Artists or participants
{
  "@context": "https://schema.org",
  "@type": "Event",
  "name": "The Adventures of Kira and Morrison",
  "startDate": "2025-07-21T19:00-05:00",
  "endDate": "2025-07-21T23:00-05:00",
  "eventStatus": "https://schema.org/EventScheduled",
  "location": {
    "@type": "Place",
    "name": "Snickerpark Stadium",
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "100 West Snickerpark Dr",
      "addressLocality": "Snickertown",
      "postalCode": "19019",
      "addressRegion": "PA",
      "addressCountry": "US"
    }
  },
  "image": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg"
  ],
  "description": "The Adventures of Kira and Morrison is coming to Snickertown.",
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/event_offer/12345",
    "price": 30,
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "validFrom": "2024-05-21T12:00"
  },
  "performer": {
    "@type": "PerformingGroup",
    "name": "Kira and Morrison"
  },
  "organizer": {
    "@type": "Organization",
    "name": "Kira and Morrison Music",
    "url": "https://kiraandmorrisonmusic.com"
  }
}

6. BreadcrumbList

Use for: Site navigation hierarchy

Required Properties:

  • itemListElement - Array of ListItem objects

ListItem Required Properties:

  • position - Sequential number starting at 1
  • name - Breadcrumb title
  • item - URL (optional for final item)
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Books",
      "item": "https://example.com/books"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Science Fiction",
      "item": "https://example.com/books/sciencefiction"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Award Winners"
    }
  ]
}

7. VideoObject

Use for: Video content, livestreams, tutorials

Required Properties:

  • name - Unique video title
  • thumbnailUrl - Multiple thumbnail URLs
  • uploadDate - ISO 8601 with timezone

Recommended Properties:

  • contentUrl - Direct video file URL
  • description - Unique description
  • duration - ISO 8601 (e.g., PT1M54S)
  • embedUrl - Video player URL
  • hasPart - Clip objects for key moments
  • publication - BroadcastEvent for LIVE badge
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "How to Make Banana Bread",
  "description": "Learn to bake delicious banana bread in 30 minutes.",
  "thumbnailUrl": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg"
  ],
  "uploadDate": "2024-03-31T08:00:00+08:00",
  "duration": "PT15M30S",
  "contentUrl": "https://example.com/video/banana-bread.mp4",
  "embedUrl": "https://example.com/embed/banana-bread",
  "hasPart": [
    {
      "@type": "Clip",
      "name": "Mixing Ingredients",
      "startOffset": 30,
      "endOffset": 120,
      "url": "https://example.com/video?t=30"
    },
    {
      "@type": "Clip",
      "name": "Baking Process",
      "startOffset": 120,
      "endOffset": 600,
      "url": "https://example.com/video?t=120"
    }
  ]
}

8. Recipe

Use for: Cooking recipes, food preparation guides

Required Properties:

  • name - Dish name
  • image - Multiple images (16x9, 4x3, 1x1; min 50K pixels)

Recommended Properties:

  • author - Recipe creator
  • aggregateRating - Average rating
  • prepTime, cookTime, totalTime - ISO 8601 durations
  • recipeYield - Servings (required if nutrition specified)
  • recipeCategory - Meal type (dinner, dessert)
  • recipeCuisine - Regional origin
  • recipeIngredient - Array of ingredients
  • recipeInstructions - HowToStep array
  • nutrition.calories - Calorie count
{
  "@context": "https://schema.org/",
  "@type": "Recipe",
  "name": "Non-Alcoholic Pina Colada",
  "image": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg"
  ],
  "author": {
    "@type": "Person",
    "name": "Mary Stone"
  },
  "datePublished": "2024-03-10",
  "description": "This non-alcoholic pina colada is everyone's favorite!",
  "recipeCuisine": "American",
  "prepTime": "PT1M",
  "cookTime": "PT2M",
  "totalTime": "PT3M",
  "keywords": "non-alcoholic, tropical, summer",
  "recipeYield": "4 servings",
  "recipeCategory": "Drink",
  "nutrition": {
    "@type": "NutritionInformation",
    "calories": "120 calories"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 5,
    "ratingCount": 18
  },
  "recipeIngredient": [
    "400ml of pineapple juice",
    "100ml cream of coconut",
    "ice"
  ],
  "recipeInstructions": [
    {
      "@type": "HowToStep",
      "name": "Blend",
      "text": "Blend 400ml of pineapple juice and 100ml cream of coconut until smooth.",
      "url": "https://example.com/recipe#step1",
      "image": "https://example.com/photos/step1.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Fill",
      "text": "Fill a glass with ice.",
      "url": "https://example.com/recipe#step2"
    },
    {
      "@type": "HowToStep",
      "name": "Pour",
      "text": "Pour the pineapple juice and coconut mixture over ice.",
      "url": "https://example.com/recipe#step3"
    }
  ],
  "video": {
    "@type": "VideoObject",
    "name": "How to Make Pina Colada",
    "description": "Watch how to make this refreshing drink.",
    "thumbnailUrl": "https://example.com/video-thumb.jpg",
    "contentUrl": "https://example.com/video.mp4",
    "uploadDate": "2024-03-10T08:00:00+00:00",
    "duration": "PT3M"
  }
}

Multiple Items on a Page

Nesting Approach

{
  "@context": "https://schema.org/",
  "@type": "Recipe",
  "name": "Banana Bread",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.7,
    "ratingCount": 123
  },
  "video": {
    "@type": "VideoObject",
    "name": "How To Make Banana Bread"
  }
}

Array Approach

[
  {
    "@context": "https://schema.org/",
    "@type": "Recipe",
    "name": "Banana Bread"
  },
  {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [...]
  }
]

Dynamic Generation with JavaScript

For SPAs, dynamic content, or CMS integrations, structured data can be generated client-side using JavaScript.

Method 1: Google Tag Manager (GTM)

Best for: Sites already using GTM, marketing teams managing structured data

Setup:

  1. Install GTM on your site
  2. Add a Custom HTML tag to your container
  3. Insert structured data block with GTM variables
  4. Publish the container
  5. Test with Rich Results Test (URL mode)

GTM Example with Variables:

<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "Recipe",
  "name": "{{recipe_name}}",
  "image": ["{{recipe_image}}"],
  "author": {
    "@type": "Person",
    "name": "{{recipe_author}}"
  },
  "datePublished": "{{recipe_date}}",
  "description": "{{recipe_description}}"
}
</script>

GTM Variable Setup:

  • Create Data Layer variables or Custom JavaScript variables
  • Extract values from page elements or data layer
  • Reduces duplication between page content and markup

Method 2: Custom JavaScript

Best for: SPAs, API-driven content, custom implementations

Basic DOM Injection:

// Create and inject structured data
function injectStructuredData(data) {
  const script = document.createElement('script');
  script.setAttribute('type', 'application/ld+json');
  script.textContent = JSON.stringify(data);
  document.head.appendChild(script);
}

// Example: Article structured data
const articleData = {
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": document.querySelector('h1').textContent,
  "image": document.querySelector('article img')?.src,
  "datePublished": document.querySelector('time')?.getAttribute('datetime'),
  "author": {
    "@type": "Person",
    "name": document.querySelector('.author-name')?.textContent
  }
};

injectStructuredData(articleData);

API-Driven Generation:

// Fetch data from API and inject structured data
fetch('https://api.example.com/recipes/123')
  .then(response => response.json())
  .then(recipe => {
    const structuredData = {
      "@context": "https://schema.org/",
      "@type": "Recipe",
      "name": recipe.title,
      "image": recipe.images,
      "author": {
        "@type": "Person",
        "name": recipe.author.name
      },
      "datePublished": recipe.publishedAt,
      "description": recipe.summary,
      "recipeIngredient": recipe.ingredients,
      "recipeInstructions": recipe.steps.map((step, i) => ({
        "@type": "HowToStep",
        "position": i + 1,
        "text": step.instruction
      }))
    };

    const script = document.createElement('script');
    script.setAttribute('type', 'application/ld+json');
    script.textContent = JSON.stringify(structuredData);
    document.head.appendChild(script);
  });

React/Next.js Example:

import Head from 'next/head';

function ProductPage({ product }) {
  const structuredData = {
    "@context": "https://schema.org",
    "@type": "Product",
    "name": product.name,
    "image": product.images,
    "description": product.description,
    "brand": {
      "@type": "Brand",
      "name": product.brand
    },
    "offers": {
      "@type": "Offer",
      "url": `https://example.com/products/${product.slug}`,
      "priceCurrency": "USD",
      "price": product.price,
      "availability": product.inStock
        ? "https://schema.org/InStock"
        : "https://schema.org/OutOfStock"
    }
  };

  return (
    <>
      <Head>
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
        />
      </Head>
      {/* Page content */}
    </>
  );
}

Method 3: Server-Side Rendering (Recommended)

For frameworks supporting SSR (Next.js, Nuxt, etc.), include structured data in the rendered HTML output for best reliability.

// Next.js getServerSideProps example
export async function getServerSideProps({ params }) {
  const product = await fetchProduct(params.id);

  return {
    props: {
      product,
      structuredData: {
        "@context": "https://schema.org",
        "@type": "Product",
        "name": product.name,
        // ... complete structured data
      }
    }
  };
}

JavaScript Generation: Important Considerations

Testing Requirements:

  • Always use URL input in Rich Results Test (not code input)
  • Code input has JavaScript limitations
  • Test the actual rendered page, not source code

Product Markup Warning: Dynamically-generated Product markup can:

  • Reduce shopping crawl frequency
  • Affect reliability for fast-changing content (price, availability)
  • Require sufficient server resources for increased Google traffic

Best Practices:

  1. Use GTM variables to extract data from page (avoid duplication)
  2. Ensure JavaScript executes before Google renders
  3. Test with Mobile-Friendly Test to verify rendering
  4. Consider SSR for critical structured data
  5. Monitor Search Console for rendering issues

Implementation Checklist

Before Deployment

  • Use JSON-LD format (recommended)
  • Include all required properties for type
  • Add recommended properties for quality
  • Use most specific Schema.org type
  • Markup matches visible page content
  • Images are crawlable and indexable
  • Dates use ISO 8601 with timezone
  • URLs are fully qualified

Testing

After Deployment

  • Submit sitemap for recrawling
  • Monitor Rich Results report in Search Console
  • Allow several days for indexing
  • Track performance changes

Common Mistakes to Avoid

  1. Marking up invisible content - Only mark up content users can see
  2. Misleading markup - Content must match what's marked up
  3. Missing required properties - Each type has mandatory fields
  4. Wrong timezone format - Always include UTC offset
  5. Using midnight (00:00:00) - Only if event actually starts at midnight
  6. Low-quality images - Use high-res images meeting size requirements
  7. Blocking Googlebot - Don't use robots.txt or noindex on structured data pages
  8. Duplicate markup inconsistency - All versions of a page need identical markup
  9. Using deprecated formats - Don't use data-vocabulary.org

Validation Tools

  1. Rich Results Test: https://search.google.com/test/rich-results
  2. Schema.org Validator: https://validator.schema.org/
  3. Search Console URL Inspection: Test live URLs
  4. Search Console Rich Results Report: Monitor status

Resources


Notes

  • Rich results are not guaranteed even with correct markup
  • Google's algorithms determine when to show rich results
  • Violations can result in manual actions (loss of rich result eligibility)
  • Keep markup updated when page content changes
  • Test after any significant changes

Source: Google Search Central Documentation Last Updated: January 2026 Version: 1.1

Changelog

  • 1.1: Added JavaScript generation section (GTM, custom JS, React/Next.js, SSR)
  • 1.0: Initial release with 8 structured data types

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

case-analyzer

No summary provided by upstream source.

Repository SourceNeeds Review
General

architect-role-skill

No summary provided by upstream source.

Repository SourceNeeds Review
General

file-categorization

No summary provided by upstream source.

Repository SourceNeeds Review