By now, most people who follow SEO are familiar with structured data, the Schema.org vocabulary, and rich snippets. Even those who know very little about SEO appreciate the benefits of adding structured data to their websites, namely that they might be able to get rich snippets in search results.
Of course, the main benefit of structured data is that it helps search engines better understand your content, which in turn helps them rank it more appropriately in search results. But we’re not here to discuss the what and why about structured data; there are plenty of other articles online that have covered that topic nicely.
Now, while Schema.org is not a comprehensive vocabulary that specifically covers every type of business — and it’s not meant to be — any business can use it to mark up their website’s content. But there’s one industry that so far has been rather limited as to what they could do with schema: restaurants.
Sure, it’s true that restaurants could always mark up the usual information such as their name, address, phone number, hours and so on. But when it came to marking up the most important information on their website — their menu — the only thing available to restaurants was one lonely menu property. That property could either point to the URL where their menu could be found, or they could mark up their entire menu simply as text. There was no way of truly marking up individual menu items and their prices, let alone specifying different types of menus such as breakfast, lunch, dinner, and so on.
Well, restaurant owners (and those who do SEO for restaurants) — rejoice! With their latest release, Schema.org has added several new properties and types that will allow marked-up menus to truly be "structured" data. And while this article is addressed particularly to restaurants, any business that serves food or drinks (such as coffee shops, bakeries, cafes, bars, and so on) can use these new properties and types to mark up their menu(s).
The new menu properties & types
The first thing you'll notice when you visit the schema.org/Restaurant page is that the menu property has been replaced with the hasMenu property. But if your current markups are still using the old menu property, don’t worry — everything will still work until you get around to updating things.
Here’s what else has been added for restaurant menus:
- A new menu type. Menus officially become entities in Schema.org with their own properties and subtypes.
- The new Menu type includes a hasMenuItem property. This property would be used to point to the (also new) MenuItem schema type, which is what would be used to mark up individual menu items.
- Since most restaurants feature a few menus such as one for breakfast, one for lunch and one for dinner, there is a new hasMenuSection property and a MenuSection type that can be used to mark up the various menus. And you can also use it to mark up the different sections of each particular menu such as the appetizers, salads, main courses, and desserts on a dinner menu.
- For each MenuItem, we’re able to mark up the name, description, price, and nutritional information. And while it’s not new to schema, you can also use the suitableForDiet property to denote if the menu item is low calorie, low fat, low salt, vegan, gluten-free, or suitable for various other restricted diets.
How to mark up restaurant menus with Schema.org
As you can see, our ability to mark up menus has become much more robust. So let’s put it all together now with some examples. We’ll be using JSON-LD, since that’s what Google prefers, and we’ll be marking up the menu of an Italian restaurant.
On the home page
On every page of the website, especially the home page, we want to point search engines in the right direction as to where the menu can be found. Keeping in mind that Google’s guidelines state that we should only mark up content that’s visible on the page, we can’t exactly include the entire menu in our home page markup unless the entire menu is published there. Instead, we’ll simply use the hasMenu property on the home page to point to the menu page, like this:
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "WebSite", "name": "Your Restaurant's Name", "url": "https://your-restaurant.com/", "publisher": { "@type": "Restaurant", "name": "Your Restaurant's Name", "hasMenu": "https://your-restaurant.com/menu/", "logo": "https://.....
In fact, on any page of your website that includes some schema markup, you could use the hasMenu property to point to the URL of the menu page.
When you have more than one menu
Now, in our example, the restaurant only serves dinner and has only one menu. But sometimes restaurants are open for breakfast, lunch, and dinner, and of course have separate menus for each. In that case, we would do this on the home page:
"hasMenu": [ { "@type": "Menu", "name": "Breakfast", "url": "https://your-restaurant.com/breakfast-menu/" }, { "@type": "Menu", "name": "Lunch", "url": "https://your-restaurant.com/lunch-menu/" }, { "@type": "Menu", "name": "Dinner", "url": "https://your-restaurant.com/dinner-menu/" } ],
Starting the menu page markup
Switching our attention to the actual menu page, let’s say that the menu was only served between 5:00pm and 11:00pm. So, on the menu page, our markup would begin like this:
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Menu", "name": "Our Menu", "mainEntityOfPage": "https://your-restaurant.com/menu/", "inLanguage": "English", "offers": { "@type": "Offer", "availabilityStarts": "T17:00", "availabilityEnds": "T23:00" },
Marking up sections of the menu
Next, we can begin marking up the various sections of the menu and the individual menu items. First, we’ll start with the appetizers. For the first appetizer, we’ll include in our markup the name, a brief description, and the price, which should be the minimum for any menu item. In our second appetizer markup example, we’ll also include an image, the nutritional information, and the fact that it’s gluten-free:
"hasMenuSection": [ { "@type": "MenuSection", "name": "Appetizers", "hasMenuItem": [ { "@type": "MenuItem", "name": "Fried Eggplant", "description": "Served with Italian red gravy.", "offers": { "@type": "Offer", "price": "7.95", "priceCurrency": "USD" } }, { "@type": "MenuItem", "name": "Fried Calamari", "description": "Served with Italian red gravy or honey mustard.", "image": "https://your-restaurant.com/images/fried-calamari.jpg", "suitableForDiet": "https://schema.org/GlutenFreeDiet", "nutrition": { "@type": "NutritionInformation", "calories": "573 calories", "fatContent": "25 grams", "carbohydrateContent": "26 grams", "proteinContent": "61 grams" }, "offers": { "@type": "Offer", "price": "7.95", "priceCurrency": "USD" } } ] },
By the way, schema dietary restriction enumerations also include DiabeticDiet, HalalDiet, HinduDiet, KosherDiet, LowCalorieDiet, LowFatDiet, LowLactoseDiet, LowSaltDiet, VeganDiet, and VegetarianDiet. Feel free to use one or more of these enumerations when they apply.
Marking up the menu items
Let’s say we’ve marked up all of the appetizers and we’re ready to begin marking up the next menu section, which in our case are the soups. Sometimes menu items such as soups are available in two or more sizes. We can mark up the available options by using a separate offer markup for each along with the eligibleQuantity property, like this:
{ "@type": "MenuSection", "name": "Soups", "hasMenuItem": [ { "@type": "MenuItem", "name": "Lobster Bisque", "offers": [ { "@type": "Offer", "price": "6.75", "priceCurrency": "USD", "eligibleQuantity": { "@type": "QuantitativeValue", "name": "Cup" } }, { "@type": "Offer", "price": "9.95", "priceCurrency": "USD", "eligibleQuantity" : { "@type": "QuantitativeValue", "name": "Bowl" } } ] }, { "@type": "MenuItem", "name": "Creole Seafood Gumbo", "offers": [ { "@type": "Offer", "price": "6.75", "priceCurrency": "USD", "eligibleQuantity": { "@type": "QuantitativeValue", "name": "Cup" } }, { "@type": "Offer", "name": "Bowl", "price": "9.95", "priceCurrency": "USD", "eligibleQuantity" : { "@type": "QuantitativeValue", "name": "Bowl" } } ] } ] },
Putting it all together
After we’ve marked up all of the soup items, we can move on to marking up the other menu sections and items using the same format. And that’s it. Putting it all together, our JSON-LD menu markup would look something like this:
<script type="application/ld+json"> { "@context":"https://schema.org", "@type":"Menu", "name": "Our Menu", "url": "https://your-restaurant.com/menu/", "mainEntityOfPage": "https://your-restaurant.com/menu/", "inLanguage":"English", "offers": { "@type": "Offer", "availabilityStarts": "T17:00", "availabilityEnds": "T23:00" }, "hasMenuSection": [ { "@type": "MenuSection", "name": "Appetizers", "hasMenuItem": [ { "@type": "MenuItem", "name": "Fried Eggplant", "description": "Served with Italian red gravy.", "offers": { "@type": "Offer", "price": "7.95", "priceCurrency": "USD" } }, { "@type": "MenuItem", "name": "Fried Calamari", "description": "Served with Italian red gravy or honey mustard.", "image": "https://your-restaurant.com/images/fried-calamari.jpg", "suitableForDiet": "https://schema.org/GlutenFreeDiet", "nutrition": { "@type": "NutritionInformation", "calories": "573 calories", "fatContent": "25 grams", "carbohydrateContent": "26 grams", "proteinContent": "61 grams" }, "offers": { "@type": "Offer", "price": "7.95", "priceCurrency": "USD" } } ] }, { "@type": "MenuSection", "name": "Soups", "hasMenuItem": [ { "@type": "MenuItem", "name": "Lobster Bisque", "offers": [ { "@type": "Offer", "price": "6.75", "priceCurrency": "USD", "eligibleQuantity": { "@type": "QuantitativeValue", "name": "Cup" } }, { "@type": "Offer", "price": "9.95", "priceCurrency": "USD", "eligibleQuantity" : { "@type": "QuantitativeValue", "name": "Bowl" } } ] }, { "@type": "MenuItem", "name": "Creole Seafood Gumbo", "offers": [ { "@type": "Offer", "price": "6.75", "priceCurrency": "USD", "eligibleQuantity": { "@type": "QuantitativeValue", "name": "Cup" } }, { "@type": "Offer", "name": "Bowl", "price": "9.95", "priceCurrency": "USD", "eligibleQuantity" : { "@type": "QuantitativeValue", "name": "Bowl" } } ] } ] }, { "@type": "MenuSection", "name": "Pastas", "description": "Entrées served with dinner salad or a cup of soup of the day.", "hasMenuItem": [ { "@type": "MenuItem", "name": "Veal Parmigiana", "description": "Tender cuts of paneed veal crowned with golden fried eggplant, Italian red gravy, mozzarella, and parmesan; served with spaghetti.", "offers": { "@type": "Offer", "price": "17.95", "priceCurrency": "USD" } }, { "@type": "MenuItem", "name": "Eggplant Parmigiana", "description": "Pan fried eggplant layered and topped with Italian red gravy, mozzarella, and parmesan baked until bubbly; served with spaghetti.", "offers": { "@type": "Offer", "price": "14.95", "priceCurrency": "USD" } } ] } ] } </script>
Of course, this is just an abbreviated example of a marked-up menu; we would certainly include more information about the restaurant as well. But hopefully you now understand how to mark up the various menu sections and items.
So, after all of that, what you’re probably wondering about now is…
Will Google use this?
Good question. To be honest, providing a definitive answer to that question right now is impossible. But if pressed, I would say, "Yes, it’s very likely."
Consider what Google already knows and does with restaurant menu content. If a restaurant has published their menu on a third-party site like SinglePlatform, Google can pull the data and display it in search results:
Fortunately, SinglePlatform marks up restaurant menus with structured data, albeit the "old way" by using the ItemList and ItemListElement schema types. But the fact that Google uses SinglePlatform’s structured data bodes well for these new menu types and properties, since they were specifically created for menus and are much more robust than what we previously had. Restaurants can do things now that they couldn’t do before with structured data.
We also know that Google’s goal is to display search results that are as accurate as possible. The problem with menus that are published on third-party sites is that they’re usually not kept up-to-date. Restaurant menus constantly change; which restaurant owner or manager has the time to update the menu on their website, on SinglePlatform, on Yelp, and on any other website that their menu is published on? I’m not telling restaurants to stop publishing their menus on those sites; they definitely still should. But by using the structured data markups that have become available, restaurant websites can now become the primary source that Google uses to gather data regarding what they serve.
And perhaps Google will begin implementing new rich snippets for restaurant menus and menu items — who knows? But at least we can now provide them with everything they need if they wanted to.
Let’s also not forget about how much voice search is growing. Wouldn’t it be awesome if, say, a pizza restaurant could attract new customers immediately because someone said, “Hey Google, which restaurants in New Orleans serve gluten-free pizza?” and Google knew exactly which restaurants did and what kinds of gluten-free pizzas they offered, all because of their thoroughly marked-up menus? That’s a situation that I could foresee happening.
The future of restaurant and menu markups
I realize that not every restaurant menu scenario is perfectly covered with these new menu properties and types, but hopefully you now at least have plenty to get started with. Keep in mind, too, that the Schema.org vocabulary continues to evolve and so will this particular area of schema. You're welcome to participate in the evolution of Schema.org through the discussions on Github. If you think that you have a great suggestion, please feel free to join the conversation.
And if you have any questions about the above, don’t hesitate to ask them in the comment section and I’ll do my best to help.
Nice recap :)
I wrote about this back in January when the restaurant menu schema was moved to the working group (my github post kicked off the menu schema proposal)
One of the things I believe it's important to focus on here is the increasing role that Google Local Search plays in many industries, and how schema is used by Google to keep many listings up to date. The addition of this menu schema will hopefully enable Google and other directories to present better data to end users, enabling higher user satisfaction... nobody likes going to a restaurant expecting a dish, only to be disappointed from an outdated menu through no fault of their own.
Hi David,
I can see where your concept of schema being used to keep "many listings up to date" is useful in many applications. It is great to see this for the restaurant industry. Given the objective of presenting better data to end users, do you think it might extend to something like a business's monthly specials or new awards won, or a museum's new exhibits?
It was fun to hear Jarno van Driel talk about The future of schema markup. As digital success is much about where search is going, what do you anticipate happening with structured data?
Great article. Is there an example of this menu or anyone else that I can see how what it looks like and how it's placed on Google?
Also is there a online restaurant schematic generator available to do this?
Thanks, Joel
Hey David,
2 more questions:
1) Client has a menu item that has quantitative pricing for some of their options, but it's based off of adding meat options to a salad. Is there Schema for that or should I just list the first price?
2) When differentiating time offerings of specific menus, is there Schema for differentiating days? So Tuesday through Saturday Lunch is offered 11am-4pm. Sunday brunch is offered 9am-3pm. Would that conflict in Schema?
Thanks for helping me think through this. I just didn't see this level of complexity in your article. Thanks!
Brad
You can, Nicholas. But I'm a firm believer in nesting everything together, at least as much as possible. So in my opinion, it's better to either nest the menu markup within the restaurant type or you can do the opposite. Having one markup on the page solely for the restaurant and another that includes both the restaurant and menu would be a bit redundant but would not cause any serious issues if it must be.
This is very good and beneficial to me, thank you for this!
I am always in the mindset that the more information you can provide the search engine the better it can display it. This is something I have been wondering about and Schema.org has been evolving to better serve the bots that read the structured data. This is also very helpful for web based applications that are looking to aggregate data pulled from the web for the end user.
At least in my country (Spain) there are very few sites that have schema.org tags on their website.
A shame because it provides a competitive advantage for positioning. I will recommend the article to a series of contacts to see if they are implementing it.
David,
Thanks for an awesome article. Trying to apply the principles in this article, but running into some hiccups with the way clients menu is setup on their website. I was wondering: could you help me out with this question?They have a menu page that shows links to their separate menus:
I followed your recommendation for adding the separate menus, per advice in the article.However, from there, do I add the different menu items under each of these menu types? Or do I do this in a separate part of Schema? Does this make sense?
That's a cool new feature to use. What if you have several locations with individual pages, and for each one a separate menu? Simply the case of adding specific schema on each menu page for each location?
Yes, that's right, richisrich. Simply use a different menu markup for each of those pages. To include the restaurant location's info, you can use the "provider" property (Menu > provider > Restaurant). I hope that makes sense and helps.
David
Can one use the Restaurant markup separately AND in addition to the menu markup? I could not find an example on schema.org that you have mentioned.
Do you think schema markup is relevant/should be used for websites like this restaurant directory (where it is currently implemented) or strictly used for actual Restaurant establishment websites?
Pagecrawler, I think that schema markup would definitely be relevant for a website such as that. Just keep in mind that it's against Google's guidelines to mark up anything that is not actually visible on the page.
Thanks for your insight David, great article!
Interesting! I also think this will quickly be used by search engines since restaurants are notoriously hard to categorize. Knowing exactly what restaurants serves Sushi opens up a ton of possibilities. I'd advice all restaurants to quickly adapt this!
The branchCode specification is a nice touch allowing you to specify different branches of the same store.
Great article - very concise. I love how easy with the specific examples it can be to implement.
I'm curious if you have an opinion for chef/owners who don't have time to keep rotating the schema menu items they have for specials? If a menu is changing daily/weekly, is it expected that they keep the menu current? Or is there a way to mark-up your site to indicate that specials are seasonal and change on a fairly frequent basis?
Thanks for the post!
Good question, Sam. For those situations, you could always mark up the "availability" of the offer to denote when the specials begin and end, similar to what was done in the "Starting the menu page markup" section. The availability properties would be added to the specific menu item.
I hope that helps and answers your question.
David
If you look in the original github discussion that generated the Menu schema proposal, one of our big concepts was around the idea of multiple menus, menus with available (by time, dates, date ranges), and the way to bring the idea of flexible pricing into a menu item (along with addons like pepperoni on pizza).
This way you have maximum flexibility.
You could create a menu that's only on a specific day, or day of the week, and then within that menu, flexible pricing on items (happy hour discounts?)
Well, very good post with informative information. I really appreciate the fact that you approach these topics from a stand point of knowledge and information.
Awesome - thank you. This will be my first schema markup attempt! *holding thumbs*
Great article, love how you connected the schema markups for restaurants to voice search. It is certainly progressing towards an attempt to fulfill more than just ordering pizzas through voice search.
Not only that, this can potentially do wonders for SME restaurants that care about SEO and use this as an early competitive advantage, which also means more business opportunities for SEO into optimising for schema markups and quick answers to cater for the growing market of voice search.
I agree, William. This is some low-hanging fruit that restaurants can take advantage of. The ones that do will likely see some good results.
Great post! Is there any example to put at Google?
It would be interesting to expand the topic with aditional information!! :)
A very interesting post David!
Much to learn and take into account when positioning locally.
Thank you and best regards!
Hey David,
When adding separate menus for adding menu items to, how would I structure this? Would it be something like the following?
<script type="application/ld+json">
{
"@context":"https://schema.org",
"@type":"Website",
"name": "Our Restaurant",
"url": "https://your-restaurant.com/",
"inLanguage": "English",
"offers": {
"@type": "Offer",
"availabilityStarts": "T17:00",
"availabilityEnds": "T23:00"
},
"hasMenu": [
{
"@type": "Menu",
"name": "Lunch",
"url": "https://your-restaurant.com/lunch-menu/",
"@type": "Offer",
"availabilityStarts": "T17:00",
"availabilityEnds": "T23:00"
},
"hasMenuSection": [
{
"@type": "MenuSection",
"name": "Appetizers",
"hasMenuItem": [
{
"@type": "MenuItem",
"name": "Fried Eggplant",
"description": "Served with Italian red gravy.",
"offers": {
"@type": "Offer",
"price": "7.95",
"priceCurrency": "USD"
}
{
"@type": "Menu",
"name": "Dinner",
"url": "https://your-restaurant.com/dinner-menu/",
"@type": "Offer",
"availabilityStarts": "T17:00",
"availabilityEnds": "T23:00"
},
"hasMenuSection": [
{
"@type": "MenuSection",
"name": "Appetizers",
"hasMenuItem": [
{
"@type": "MenuItem",
"name": "Fried Eggplant",
"description": "Served with Italian red gravy.",
"offers": {
"@type": "Offer",
"price": "7.95",
"priceCurrency": "USD"
},
{
"@type": "Menu",
"name": "Sunday Brunch",
"url": "https://your-restaurant.com/sunday-brunch-menu/"
"@type": "Offer",
"availabilityStarts": "T17:00",
"availabilityEnds": "T23:00"
},
"hasMenuSection": [
{
"@type": "MenuSection",
"name": "Appetizers",
"hasMenuItem": [
{
"@type": "MenuItem",
"name": "Fried Eggplant",
"description": "Served with Italian red gravy.",
"offers": {
"@type": "Offer",
"price": "7.95",
"priceCurrency": "USD"
},
{
"@type": "Menu",
"name": "Beer Wine & Dessert",
"url": "https://your-restaurant.com/beer-wine-dessert/"
"@type": "Offer",
"availabilityStarts": "T17:00",
"availabilityEnds": "T23:00"
},
"hasMenuSection": [
{
"@type": "MenuSection",
"name": "Appetizers",
"hasMenuItem": [
{
"@type": "MenuItem",
"name": "Fried Eggplant",
"description": "Served with Italian red gravy."
,
"offers": {
"@type": "Offer",
"price": "7.95",
"priceCurrency": "USD"
},
]
Hi braderb. Looks like there's a coding error in your markup but I think you're on the right track.
As a SEO Professional! I always looking for new updates on Moz and Search Engine Land, DubSEO, Found, etc. company updates. As they are very legit site of industry. I always prefer to watch the White Board friday.
I would definitely implement these features in our client business which are in UK and Canada. The part Marking up the menu items and The future of restaurants around the world and menu markups explained well and and as we are a Digital marketing team of Induji Technologies Pvt. Ltd. we do appreciate your contribution to online marketing.
Looking for your new updates.
Thanks!
I'm not sure but it would be great if we can use Restaurant Menu and Review Markup together. Thanks for this article David.
Great explanation of how to implement Schema for a restaurant menu. I think that Google will begin to show this in their search results very soon and the first movers will definitely have an advantage until others catch up.
Excellent article.
I implemented schema features in my clients' websites, which are in USA, Canada, and UK and achieved excellent results.
Search engines are always trying to learn more about your business, information such as the type of food you serve, your contact information, hours of operations, menu, blog posts, review, etc.
Structured data can help you to send the right signals to search engines about your business and content.
While using schema, it is good to use several locations with individual pages, restaurant location's information and different menu markup for each of the pages.
Using right schema will boost your CTR and will help in local SEO.
Ha! Ha!! Finally, This is great for restaurants also SEO Account managers the above markup codes makes me hungry though :) just imagine an SEO account manager that has to markup various restaurant menu weekly.. now will it get much use or do you just mark up the most important menu especially the restaurants signature dish menu which really never changes? As we all know estaurant do change their menu regularly. Overall great that it's finally available if there's need for it.
I don't work with many restaurants yet, but I am a big fan of Schema and this is a great resource to have! Thanks for the overview and tips