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:

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 carousel. 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

What you'll need

Click the following link to download all the code for this codelab:

Download source code

Unpack the downloaded zip file. This will unpack a root folder (structured-data-codelab), which contains final and original versions of the html page. We will be doing our work in the original-party-coffee-cake-recipe.html file, and you can check the final-party-coffee-cake-recipe.html file to verify your work.

We're going to start with recipe structured data because it's the most applicable data type for our example site (which is a site about recipes). 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 in mobile image Search results, voice guidance on the Google Home, and a content action on the Google Assistant.

Set up your workspace

Start by opening the original-party-coffee-cake-recipe.html file in a text editor. Then copy the code snippet into the Structured Data Testing Tool (SDTT) by following the steps below:

  1. Open the SDTT.
  2. Click Code Snippet.
  3. Copy the HTML source (original-party-coffee-cake-recipe.html) to the code snippet box in the Structured Data Testing Tool.
  4. Click Run Test.

You should see a "Detected" response in the right panel of SDTT because your HTML snippet doesn't have any structured data yet.

Define the type of structured data

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

  1. In your code snippet in SDTT, create a <script> element with the type set to application/ld+json in the <head> of the page.
  1. Inside the <script> element, set @context to http://schema.org to tell Google you're using schema.org structured data.
  2. Set @type to Recipe to tell Google what kind of thing you're describing; in this case, it's a recipe. You should have this so far:
<html>
<head>
...
<script type="application/ld+json">
{
  "@context": "http://schema.org/",
  "@type": "Recipe"
}
</script>
</head>
</html>

Add required and recommended properties

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 is less likely to work with certain 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 SDTT, enter the name of the dish (which is Party Coffee Cake) as the value for name.
    You should have this so far:
<html>
<head>
...
<script type="application/ld+json">
{
  "@context": "http://schema.org/",
  "@type": "Recipe",
  "name": "Party Coffee Cake"
}
</script>
</head>
</html>
  1. Click Validate in SDTT to test your sample. It recognizes the content type ("Recipe") and name ("Party Coffee Cake"), but says that other properties are required.
  2. Repeat steps 1-3 for the other required properties listed in the documentation.
  3. Add the recommended properties to drive better engagement in Search. Here's how your recipe sample 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": [
     {
    "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",
    "interactionCount": "2347",
    "expires": "2019-02-05T08:00:00+08:00"
   }
  ]
}
</script>
</head>
</html>
  1. Now that you've added the properties, let's validate the sample. In SDTT, click Validate ▶. 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.

Since we already added Recipe structured data, we're going to embed a review and aggregate ratings within recipe structured data (rather than other approaches, like a simple review or review with rating).

Add an individual review

Let's add the first individual review from Julia Benson.

  1. Add a property to the recipe, whose value is another entity with a "@type" of "Review". You should have this so far:
<html>
<head>
...
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Recipe",
// other recipe structured data
"review": {
  "@type": "Review"
 }
}
</script>
</head>
</html>
  1. Add the required properties that are listed in the Common review properties section of the developer documentation. The first required property is author (itemReviewed can be omitted since our example is embedded within Recipe).
  2. Set the @type of the author to Person.
  3. Enter Julia Benson as the value for author. You should have this so far:
<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. Continue to add the rest of the required properties for Review listed in the Common review properties section of the developer 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 what a completed review might look like:
<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. Now that you've added the properties, let's validate the sample. In SDTT, click Validate ▶. 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

We're going to add the aggregate rating, which is the average rating based on multiple ratings or reviews for this recipe.

  1. Add aggregateRating at the same level of indentation as "@type": "Recipe".
  2. Set @type to AggregateRating. You should have this so far:
<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. Now that you've added the properties, let's validate the sample. In SDTT, click Validate ▶. Ideally, you should see 0 errors and 0 warnings. If you see an error or warning, read the message and fix the problem.
  1. You can also preview how the current structured data might look in search results. Make sure you have the entire HTML snippet with the JSON-LD structured data in SDTT. In SDTT, click the Preview button.

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": [
            {
            "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",
            "interactionCount": "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>

What we've covered

Learn more

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