Add structured data to your web pages

1. Overview

Google Search works hard to understand the content of a web page. You can help us by providing explicit clues about the meaning of a page with structured data.

Structured data provides a way to standardize information about a page and classify the page content. We also use structured data to enable special search result features and enhancements. For example, a recipe page with valid structured data can be eligible to appear in a graphical search result, which we call a rich result in a host carousel:

3c4b35df592b40b2.png

What you'll build

This codelab walks you through adding several types of structured data to a simple HTML site, including where to place your structured data on a site and how to validate structured data.

We're going to focus on a recipe site for our example because it's easy to test and includes several add-on features, like reviews and carousels. The techniques you learn can help drive traffic to your site, not just recipe sites.

At the end of the codelab, you'll have a sample site that's eligible for rich results in Google Search. You should feel confident implementing other structured data types.

What you'll learn

  • How to add structured data to a simple HTML site
  • How to avoid common pitfalls
  • How to test and validate structured data

What you'll need

  • A recent version of Chrome or other modern web browser
  • The sample code that is provided in this codelab
  • Basic understanding of HTML and JSON syntax

2. Copy the Glitch sample

You'll use a sample web page for this codelab. The project files are stored in Glitch, which is a tool for creating web apps and code projects. To create your own, editable copy of the project for this codelab, click Copy the Glitch project:

3. Add recipe structured data

Since our sample site is a recipe blog, we're going to start with recipe structured data. Recipe structured data can provide a rich result that can include rich information, like a description of your recipe, cooking and preparation times, and nutrition information. Your content may also automatically enable a recipe badge for Google Images on mobile devices, voice guidance on the Google Home, and a content action on the Google Assistant.

Define the type of structured data

To define the type of structured data, follow the steps below:

  1. In index.html, create a <script> element with the type set to application/ld+json in the <head> of the page.
                        <head> <script type="application/ld+json"> </script> </head>                                              
  1. Inside the <script> element, tell Google you're using schema.org structured data by setting @context to http://schema.org.
                        <head> <script type="application/ld+json"> {   "@context": "http://schema.org/", </script> </head>                                              
  1. To tell Google what kind of thing you're describing, set @type to Recipe.
                        <html> <head> <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe" } </script> </head> </html>                                              

Each structured data type supports a list of required and recommended properties that give Google more information about the thing being described. These requirements and recommendations power various Google products and features. There is nothing wrong with your page if it's missing some properties; it just means that it's less likely to work with certain Search features.

  1. Look at the list of required properties in the Recipe documentation and locate the name property to see if there are additional guidelines for this property.
  2. In index.html, enter the name of the dish (which is Party Coffee Cake) as the value for name after "@type": "Recipe".
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   "name": "Party Coffee Cake" } </script> </head> </html>                                              
  1. Continue to add the other required properties listed in the documentation.
  2. Add the recommended properties to drive better engagement in Search. Here's how your structured data should look:
                        <html> <head> ... <script type="application/ld+json">   {   "@context": "http://schema.org/",   "@type": "Recipe",   "name": "Party Coffee Cake",   "image": "https://www.leannebrown.com/wp-content/uploads/2016/12/up-close-pear-cake.jpg",   "author": {     "@type": "Person",     "name": "Mary Stone"   },   "datePublished": "2018-03-10",   "description": "This coffee cake is awesome and perfect for parties.",     "prepTime": "PT20M",     "cookTime": "PT30M",     "totalTime": "PT50M",     "recipeYield": "10 servings",     "recipeCategory": "Dessert",     "recipeCuisine": "American",     "keywords": "cake for a party, coffee",     "nutrition": {       "@type": "NutritionInformation",       "calories": "270 calories"      },       "recipeIngredient": [         "2 cups of flour",         "3/4 cup white sugar",         "2 teaspoons baking powder",         "1/2 teaspoon salt",         "1/2 cup butter",         "2 eggs",         "3/4 cup milk"        ],     "recipeInstructions": [       {       "@type": "HowToStep",       "text": "Preheat the oven to 350 degrees F. Grease and flour a 9x9 inch pan."       },       {       "@type": "HowToStep",       "text": "In a medium bowl, combine flour, sugar, and cinnamon."       },       {       "@type": "HowToStep",       "text": "Mix in butter until the entire mixture is crumbly."       },       {       "@type": "HowToStep",       "text": "In a large bowl, combine flour, sugar, baking powder, and salt."       },       {       "@type": "HowToStep",       "text": "Mix in the butter."       },       {       "@type": "HowToStep",       "text": "Spread into the prepared pan."       },       {       "@type": "HowToStep",       "text": "Sprinkle the streusel mixture on top of the cake."       },       {       "@type": "HowToStep",       "text": "Bake for 30 to 35 minutes, or until firm."       },       {       "@type": "HowToStep",       "text": "Allow to cool."      }   ],   "video": [      {     "@type": "VideoObject",      "name": "How to make a Party Coffee Cake",     "description": "This is how you make a Party Coffee Cake.",     "thumbnailUrl": [       "https://example.com/photos/1x1/photo.jpg",       "https://example.com/photos/4x3/photo.jpg",       "https://example.com/photos/16x9/photo.jpg"      ],     "contentUrl": "http://www.example.com/video123.flv",     "embedUrl": "http://www.example.com/videoplayer.swf?video=123",     "uploadDate": "2018-02-05T08:00:00+08:00",     "duration": "PT1M33S",     "interactionStatistic": {       "@type": "InteractionCounter",       "interactionType": { "@type": "http://schema.org/WatchAction" },       "userInteractionCount": 2347      },     "expires": "2019-02-05T08:00:00+08:00"    }   ] } </script> </head> </html>                                              

Validate the structured data

To validate your data, you need to use the URL for your Glitch app. To find the URL for your app in Glitch, click Share, select Live App, and then copy the URL.

In the Rich Results Test, enter the URL for your Glitch app and click Test URL. Ideally, you should see 0 errors and 1 warning. (You will add aggregateRating in the next step.) If you see an error or more than one warning, read the message and fix the problem.

4. Embed reviews within recipe structured data

Since you already added Recipe structured data, the next step is to embed a review and aggregate ratings within the Recipe structured data (rather than other approaches, like a simple review or review with rating).

Add an individual review

To add the first individual review from Julia Benson, follow the steps below:

  1. In index.html, add another entity with a "@type" of "Review".
                        <html> <head> ... <script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Recipe", // other recipe structured data "review": {   "@type": "Review"  } } </script> </head> </html>                                              
  1. To add the first required review property, set the @type of the author to Person.
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   "review": {     "@type": "Review",     "author": {       "@type": "Person",     }   } } </script> </head> </html>                                              
  1. Enter Julia Benson as the value for author.
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   "review": {     "@type": "Review",     "author": {       "@type": "Person",       "name": "Julia Benson"     }   } } </script> </head> </html>                                              
  1. Add the remaining required properties that are listed in the documentation.
  2. Add the recommended properties to drive better engagement in Search. You can use the name of the recipe site (The cake makery) as the value for publisher. Here's how a completed review should look:
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   // ...   // other recipe structured data   // ...   "review": {     "@type": "Review",     "reviewRating": {       "@type": "Rating",       "ratingValue": "4",       "bestRating": "5"     },     "author": {       "@type": "Person",       "name": "Mary Stone"     },     "datePublished": "2018-05-01",     "reviewBody": "This cake is delicious!",     "publisher": "The cake makery"   } } </script> </head> </html>                                              
  1. In the Structured Data Testing Tool, enter the URL for your Glitch app and click Run Test. Ideally, you should see 0 errors and 1 warning for aggregateRating. If you see an error or more than one warning, read the message and fix the problem.

Add the aggregate rating for all reviews

The aggregate rating for all reviews is the average rating based on multiple ratings or reviews for this recipe. To add the aggregate rating, follow the steps below:

  1. In index.html, add aggregateRating at the same level of indentation as "@type": "Recipe".
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   // other recipe structured data   // review structured data   "aggregateRating": {   } } </script> </head> </html>                                              
  1. Set @type to AggregateRating.
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   // other recipe structured data   // review structured data   "aggregateRating": {     "@type": "AggregateRating",   } } </script> </head> </html>                                              
  1. Add the required properties that are listed in the Aggregated rating properties section of the developer documentation.
  1. The first required property is ratingCount. Set the value for ratingCount to 18.
  2. Add the ratingValue. The ratingValue is the average rating for this recipe, which we're going to set as 4. Here's how a completed aggregate rating for recipes should look:
                        <html> <head> ... <script type="application/ld+json"> {   "@context": "http://schema.org/",   "@type": "Recipe",   // other recipe structured data   // review structured data   "aggregateRating": {     "@type": "AggregateRating",     "ratingCount": "18",     "ratingValue": "4"   } } </script> </head> </html>                                              
  1. In the Rich Results Test, enter the URL for your Glitch app and click Test URL. Ideally, you should see 0 errors and 0 warnings. If you see an error or warning, read the message and fix the problem.
  1. To preview how the page could look in search results, click Preview Results in the Rich Results Test. f4dd7a85875518d4.png

9ffc97e46aad6cb7.png

Final JSON-LD sample

Here's how your completed JSON-LD recipe might look on an HTML page:

                        <!doctype HTML> <html class="no-js">     <head>         <meta charset=utf-8>         <title>Home of the best cakes - Recipe XYZ</title>         <meta name="viewport" content="width=device-width,initial-scale=1">         <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,700">         <link rel="manifest" href="manifest.json">         <link rel="stylesheet" href="third_party/css/bootstrap.css">         <link rel="stylesheet" href="third_party/css/mysite.css">         <meta http-equiv="x-ua-compatible" content="ie=edge">         <meta name="description" content="This shop is awesome.">         <script type="application/ld+json">         {         "@context": "http://schema.org/",         "@type": "Recipe",         "name": "Party Coffee Cake",         "image": [             "https://www.leannebrown.com/wp-content/uploads/2016/12/up-close-pear-cake.jpg"         ],         "author": {             "@type": "Person",             "name": "Mary Stone"         },         "datePublished": "2018-03-10",         "description": "This coffee cake is awesome and perfect for parties.",                   "prepTime": "PT20M",         "cookTime": "PT30M",         "totalTime": "PT50M",         "recipeYield": "10 servings",         "recipeCategory": "Dessert",         "recipeCuisine": "American",         "keywords": "cake for a party, coffee",         "nutrition": {             "@type": "NutritionInformation",             "calories": "270 calories"         },         "recipeIngredient": [             "2 cups of flour",             "3/4 cup white sugar",             "2 teaspoons baking powder",             "1/2 teaspoon salt",             "1/2 cup butter",             "2 eggs",             "3/4 cup milk"            ],         "recipeInstructions": [               {               "@type": "HowToStep",               "text": "Preheat the oven to 350 degrees F. Grease and flour a 9x9 inch pan."               },               {               "@type": "HowToStep",               "text": "In a medium bowl, combine flour, sugar, and cinnamon."               },               {               "@type": "HowToStep",               "text": "Mix in butter until the entire mixture is crumbly."               },               {               "@type": "HowToStep",               "text": "In a large bowl, combine flour, sugar, baking powder, and salt."               },               {               "@type": "HowToStep",               "text": "Mix in the butter."               },               {               "@type": "HowToStep",               "text": "Spread into the prepared pan."               },               {               "@type": "HowToStep",               "text": "Sprinkle the streusel mixture on top of the cake."               },               {               "@type": "HowToStep",               "text": "Bake for 30 to 35 minutes, or until firm."               },               {               "@type": "HowToStep",               "text": "Allow to cool."              }           ],         "video": [             {             "@type": "VideoObject",              "name": "How to make a Party Coffee Cake",             "description": "This is how you make a Party Coffee Cake.",             "thumbnailUrl": [               "https://example.com/photos/1x1/photo.jpg",               "https://example.com/photos/4x3/photo.jpg",               "https://example.com/photos/16x9/photo.jpg"              ],             "contentUrl": "http://www.example.com/video123.flv",             "embedUrl": "http://www.example.com/videoplayer.swf?video=123",             "uploadDate": "2018-02-05T08:00:00+08:00",             "duration": "PT1M33S",             "interactionStatistic": {               "@type": "InteractionCounter",               "interactionType": { "@type": "http://schema.org/WatchAction" },               "userInteractionCount": 2347             },             "expires": "2019-02-05T08:00:00+08:00"            }           ],         "aggregateRating": {             "@type": "AggregateRating",             "ratingValue": "5",             "ratingCount": "18"             },         "review": {             "@type": "Review",             "reviewRating": {                 "@type": "Rating",                 "ratingValue": "4",                 "bestRating": "5"             },             "author": {                 "@type": "Person",                 "name": "Mary"             },             "datePublished": "2018-05-01",             "reviewBody": "This cake is delicious!",             "publisher": "The cake makery"             }          }         </script>     </head>      <body>         <!-- Navigation -->         <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">             <div class="container">                 <!-- Brand and toggle get grouped for better mobile display -->                 <div class="navbar-header">                     <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">                         <span class="sr-only">Toggle navigation</span>                         <span class="icon-bar"></span>                         <span class="icon-bar"></span>                         <span class="icon-bar"></span>                     </button>                     <a class="navbar-brand" href="index.html">The cake makery</a>                 </div>                 <!-- Collect the nav links, forms, and other content for toggling -->                 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">                     <ul class="nav navbar-nav navbar-right">                         <li>                             <a href="recipes.html">Recipes</a>                         </li>                         <li>                             <a href="about.html">About</a>                         </li>                         <li>                             <a href="contact.html">Contact</a>                         </li>                     </ul>                 </div>                 <!-- /.navbar-collapse -->             </div>             <!-- /.container -->         </nav>              <!-- Page Content -->         <div class="container">              <!-- Page Heading/Breadcrumbs -->         <div class="row">                 <div class="col-lg-12">                     <h1 class="page-header">Recipe XYZ                         <small>Subheading</small>                     </h1>                     <ol class="breadcrumb">                         <li><a href="index.html">Home</a>                         </li>                         <li><a href="recipes.html">Recipes</a>                         </li>                         <li class="active">Coffee Cake</li>                     </ol>                 </div>             </div>             <!-- /.row -->                  <!-- Features Section -->             <div class="row">                 <div class="col-lg-12">                     <h2 class="page-header">Party Coffee Cake</h2>                 </div>                 <div class="col-md-6">                     <p><strong>Recipe author</strong>: Mary Stone</p>                     <p><strong>Date published</strong>: March 10, 2018</p>                     <p>This coffee cake is awesome and perfect for parties.</p>                     <h2>Ingredients</h2>                     <ul>                         <li>2 cups of flour</li>                         <li>3/4 cup white sugar</li>                         <li>2 teaspoons baking powder</li>                         <li>1/2 teaspoon salt</li>                         <li>1/2 cup butter</li>                         <li>2 eggs</li>                         <li>3/4 cup milk</li>                         <li>1 teaspoon vanilla extract</li>                         <li>1 1/2 teaspoon group cinnamon</li>                         <h2>Directions</h2>                         <p>Yield: 10 servings</p>                         <p>Prep time: 20 minutes</p>                         <p>Cook time: 30 minutes</p>                         <p>Total time: 50 minutes</p>                         <li>Preheat the oven to 350 degrees F. Grease and flour a 9x9 inch pan.</li>                         <li>Make the streusal topping. In a medum bowl, combine flour, sugar, and cinnamon. Mix in butter                              until the entire mixture is crumbly.</li>                         <li>In a large bowl, combine flour, sugar, baking powder, and salt. Mix in the butter. Mix in the                              milk, egg, and vanilla. Spread into the prepared pan. </li>                         <li>Sprinkle the streudal mixture on top of the cake.</li>                         <li>Bake for 30 to 35 minutes, or until firm. Allow to cool.</li>                         </ol>                     <h2>Nutrition facts</h2>                     <p>Per slice: 270 calories; 12 g fat; 37 carbohydrates; 2 g protein; 45 mg cholesterol;                          195 mg sodium.</p>                 </div>                 <div class="col-md-6">                     <img class="img-responsive" src="cake.jpg" alt="Party coffee cake">                 </div>             </div>             <!-- /.row -->              <hr>              <!-- Reviews Section -->             <div class="row">                 <div class="col-lg-12">                     <h2 class="page-header">18 user reviews</h2>                 </div>                 <!-- list of reviews -->                 <div class="col-md-6">                     <p><span class="review-date">2018-05-01</span>                         <span class="review-stars">****</span>                         <span class="review-name">Mary</span>                         <span class="review-text">This coffee cake is delicious!</span></p>                     <p><span class="review-date">2018-05-04</span>                         <span class="review-stars">*****</span>                         <span class="review-name">Susan</span>                         <span class="review-text">The cake instructions are superbly crafted and accurately designed.</span></p>                     <p><span class="review-date">2018-02-01</span>                         <span class="review-stars">***</span>                         <span class="review-name">Mark</span>                         <span class="review-text">The cake also includes paprika, which makes me nervous.</span></p>                     <p><span class="review-date">2018-02-01</span>                         <span class="review-stars">***</span>                         <span class="review-name">Vanessa</span>                         <span class="review-text">I think the candle on top looks very cool, but only if you have the time to bother with it.</span></p>                     <p><span class="review-date">2018-02-01</span>                         <span class="review-stars">***</span>                         <span class="review-name">Simone</span>                         <span class="review-text">I like that they added sprinkles to the top.</span></p>                     <p><span class="review-date">2018-02-21</span>                         <span class="review-stars">****</span>                         <span class="review-name">Maurice</span>                         <span class="review-text">The coffee cake was easy to make, and tasted great.</span></p>                      <p><a href=#>(Expand all reviews)</a></p>                 </div>                 <!-- /list of reviews -->                                  <!-- submit review column -->                 <div class="col-md-6">                     <form name="sentMessage" id="newReview" novalidate>                         <div>Leave your review here!</div>                          <div class="control-group form-group">                             <div class="controls">                                 <label>Your Name:</label>                                 <input type="text" class="form-control" id="name"                                      required data-validation-required-message="Please enter your name.">                                 <p class="help-block"></p>                             </div>                         </div>                         <div class="control-group form-group">                             <div class="controls">                                 <label>Rating:</label>                                  <select name="review" id="review" class="form-control"                                      required data-validation-required-message="Please select a rating.">                                     <option value="5">5 Stars (*****)</option>                                     <option value="4">4 Stars (****)</option>                                     <option value="3">3 Stars (***)</option>                                     <option value="2">2 Stars (**)</option>                                     <option value="1">1 Star  (*)</option>                                 </select>                                 <p class="help-block"></p>                             </div>                         </div>                         <div class="control-group form-group">                             <div class="controls">                                 <label>Review text:</label>                                 <textarea rows="5" cols="100" class="form-control" id="message"                                      required data-validation-required-message="Please enter your message"                                      maxlength="999" style="resize:none"></textarea>                             </div>                         </div>                         <div id="success"></div>                         <!-- For success/fail messages -->                         <button type="submit" class="btn btn-primary">Submit review</button>                     </form>                 </div>             </div>              <!-- /.row -->                              <hr>                  <!-- Call to Action Section -->             <div class="well">                 <div class="row">                     <div class="col-md-8">                         <p>Try out our summer cake recipe!</p>                     </div>                     <div class="col-md-4">                         <a class="btn btn-lg btn-primary btn-block" href="#">Bake that cake</a>                     </div>                 </div>             </div>                  <hr>                  <!-- Footer -->             <footer>                 <div class="row">                     <div class="col-lg-12">                         <p>Copyright &copy; Home of the best cakes, 2018 |                              <a href="http://html5-templates.com/" target="_blank" rel="nofollow">HTML5 Templates</a></p>                     </div>                 </div>             </footer>              </div>         <!-- /.container -->                </body> </html>                                              

5. Finished!

What we've covered

  • How to add structured data to a simple HTML site
  • How to avoid common pitfalls
  • How to test and validate structured data

Learn more

Keep learning about structured data by checking out the following resources:

  • Discover different features and types of markup available in the Search Gallery
  • Use a sitemap file to help search engine crawlers find your URLs
  • Get help with your structured data in the Webmaster Forum
  • Monitor your site with Search Console