Correct structured data formatting for list of events with JSON-LD - schema.org

I am attempting to create structured data for a list of events. I currently have the following:
"#context": "http:\/\/schema.org",
"#type": "ItemList",
"name": "Forthcoming Shows",
"url": "http:\/\/example.com\/",
"itemListElement": [
{
"#type": "Event",
"name": "test event",
"startDate": "21\/07\/2020",
"endDate": "24\/07\/2020",
"description": "description here",
"position": 1,
"url": "http:\/\/example.com/",
"location": [
{
"#type": "Place",
"name": "Venue name",
"address": "Venue address"
}
]
},
etc
]
Google's Structured data testing tool objects to the position as The property position is not recognized by Google for an object of type Event, but if I leave it out the tool objects because A value for the position field is required.
I could siply use a ListItem as the type, but then start date and end date are invalid and I rather hoped that a list of events would allow for these event details to be included.
Unfortunately I can't find any examples of a list of events or and events calendar to reference. What would the correct/best structure be?

The position is property of ListItem (Not of the event).
To fix your issue you should use a nested object (itemListElement > item (type event)).
Basic outline (Missing some properties for shorter code):
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "ItemList",
"name": "Basic list",
"numberOfItems": 2,
"itemListElement": [
{
"#type": "ListItem",
"position": 1,
"item": {
"#type": "event",
"name": "hello"
}
},
{
"#type": "ListItem",
"position": 2,
"item": {
"#type": "event",
"name": "world"
}
}
]
}
</script>
"THE PROBLEM"
Add structured data to your event pages. Currently, the event
experience on Google only supports pages that focus on a single event
https://developers.google.com/search/docs/data-types/event
Anyway, your markup could look something like this (Again google not support this for rich results true to June 2020):
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "ItemList",
"url": "http://hello.com",
"numberOfItems": "2",
"itemListElement": [
{
"#type": "ListItem",
"position": 1,
"name": "Event One",
"item": {
"#type": "Event",
"name": "If Not For You",
"url": "http://hello.com#one",
"startDate": "2025-07-21T19:00-05:00",
"location": {
"name": "Snickerpark Stadium",
"address": "Paris"
}
}
},/*item two*/
{
"#type": "ListItem",
"position": 2,
"name": "Event Two",
"item": {
"#type": "Event",
"name": "Event Two",
"url": "http://hello.com#two",
"startDate": "2025-07-21T19:00-05:00",
"location": {
"name": "Empire Stadium",
"address": "London"
}
}
}
]
}
</script>
One more issue. Google uses a very close outline for summary-page (Keep this in mind):
Defines an ItemList, where each ListItem has only three properties:
#type (set to "ListItem"), position (the position in the list), and
url (the URL of a page with full details about that item https://developers.google.com/search/docs/data-types/carousel

The list for events is not supported by Google:
Each event MUST have a unique URL (a leaf page) and markup on that
URL.

Related

What is the correct structure to represent a list of movie showtimes on the same page?

I am building a website to reference movie showtimes.
The site shows a now playing page with a list of movies, each movie has a page with the upcoming showtimes.
I added some structured data to enhance the way search engines sees the data on my website.
Here is what I have so far:
{
"#context": "https://schema.org",
"#type": "ItemList",
"numberOfItems": 2,
"itemListElement": [
{
"#type": "ListItem",
"name": "Screening Event 1",
"position": 1,
"item": {
"#context": "https://schema.org",
"#type": "ScreeningEvent",
"startDate": "2021-09-18T15:15:00.000Z",
"url": "http://localhost:3000/film/Boite-noire/663260#6144ab7a22b6d900165aa836",
"inLanguage": "fr",
"location": {
"#context": "https://schema.org",
"#type": "MovieTheater",
"name": "Pathé Tunis City",
"url": "http://localhost:3000/medium/pathe-tunis-city"
},
"workPresented": {
"#context": "https://schema.org",
"#type": "Movie",
"name": "Boîte noire",
"image": "https://image.tmdb.org/t/p/w300_and_h450_bestv2/jIfFFC4YwiI8TVaGtbl1eT9BRaI.jpg",
"url": "http://localhost:3000/film/Boite-noire/663260",
"sameAs": "https://imdb.com/title/tt10341034",
"director": {
"#type": "Person",
"name": "Yann Gozlan"
}
}
}
},
{
"#type": "ListItem",
"name": "Screening Event 2",
"position": 2,
"item": {
"#context": "https://schema.org",
"#type": "ScreeningEvent",
"startDate": "2021-09-18T20:15:00.000Z",
"url": "http://localhost:3000/film/Boite-noire/663260#6144ab8522b6d900165aa837",
"inLanguage": "fr",
"location": {
"#context": "https://schema.org",
"#type": "MovieTheater",
"name": "Pathé Tunis City",
"url": "http://localhost:3000/medium/pathe-tunis-city"
},
"workPresented": {
"#context": "https://schema.org",
"#type": "Movie",
"name": "Boîte noire",
"image": "https://image.tmdb.org/t/p/w300_and_h450_bestv2/jIfFFC4YwiI8TVaGtbl1eT9BRaI.jpg",
"url": "http://localhost:3000/film/Boite-noire/663260",
"sameAs": "https://imdb.com/title/tt10341034",
"director": {
"#type": "Person",
"name": "Yann Gozlan"
}
}
}
}
]
}
Is there a better way to represent this kind of information without repeating data ?
My suggestion gave the google guide for Carousel --> Single, all-in-one-page list:
{
"#context": "https://schema.org",
"#type": "Movie",
...
"#id":"https://cinema.com/lordofrings.html",
"name":"Lord of the rings",
"subjectOf":{
"#type": "ItemList",
"itemListElement": [
{
"#type": "ListItem",
"position": "1",
"item": {
"#type": "ScreeningEvent",
"url": "https://cinema.com/lordofrings.html#15",
"startDate": "2021-09-18T15:00:00+01:00"
}
},
{
"#type": "ListItem",
"position": "2",
"item": {
"#type": "ScreeningEvent",
"url": "https://cinema.com/lordofrings.html#18",
"startDate": "2021-09-18T18:00:00+01:00"
}
}
]
}
}
For ellipsis, set the required movie info and add all the required and recommended properties for the Google Rich Results Test.

Organization logo needs url

I have the following JSON-LD:
{
"mainEntity": {
"itemListElement": [{
"author": {
"#id": "https://www.example.co.uk/gardens-and-driveways/blog/author/test",
"image": "https://www.example.co.uk/blog/authors/no-image",
"name": "Test Author",
"#type": "Person"
},
"publisher": {
"#id": "http://www.example.co.uk",
"logo": "https://www.example.co.uk/logo.png",
"name": "Test Organisation",
"#type": "Organization"
},
"datePublished": "2015-08-10T11:04:33",
"headline": "Blog headline",
"image": "https://www.example.co.uk/blog-image.jpg",
"url": "https://www.example.co.uk/blog-article",
"name": "Blog Article",
"#type": "BlogPosting"
}],
"#type": "ItemList"
},
"url": "https://www.example.co.uk/blog-category-page",
"#context": "https://schema.org/",
"description": "Blog articles in this category",
"name": "Blog category",
"#type": "CollectionPage"
}
Which if I try to validate using Google's validator will throw the error for the publishers organisation logo field.
https://www.example.co.uk/logo.png (A value for the url field is required.)
Looking at the documentation for Organization it says that logo can be a string or an image type so why is this failing?
Conversely, if you just try to validate the Organization bit by itself, it will pass:
{
"#id": "http://www.example.co.uk",
"logo": "https://www.example.co.uk/logo.png",
"name": "Test Organisation",
"#type": "Organization"
}
Googles own guidelines are a bit stricter when it comes to the publisher entity for an Article:
https://developers.google.com/search/docs/data-types/article
It shows the publishers image needs to be marked up as an ImageObject.

Resume (work history and organization) format with JSON-LD and Schema.org vocab

Let's say you have a profile page that features a mainEntity that's a Person. And you'd like to list that person's work and education history, similar to a resume.
Schema.org's Occupation example 4, illustrates how to use Role and hasOccupation to associate an array of work history, like so:
{
"#context": "http://schema.org",
"#type": "Person",
"name": "Jane Smith",
"sameAs": "http://en.wikipedia.org/wiki/Jane_Smith",
"worksFor": {
"#type": "Organization",
"name": "McKinsey & Company",
"url" : "http://www.mckinsey.com"
},
"hasOccupation": [ {
"#type": "Role",
"hasOccupation": {
"#type": "Occupation",
"name": "Management Consultant"
},
"startDate": "2016-04-21"
}, {
"#type": "Role",
"hasOccupation": {
"#type": "Occupation",
"name": "Chief Strategic Officer"
},
"startDate": "2013-11-14",
"endDate": "2016-03-22"
}, {
"#type": "Role",
"hasOccupation": {
"#type": "Occupation",
"name": "Vice President of Sales"
},
"startDate": "2009-09-20",
"endDate": "2013-10-14"
}
]
}
Only the occupation name is included. Not the Organization associated with that Occupation.
Is it possible to detail a resume more extensively this way with the Schema.org vocab? (Similar to Microformats hresume)
Side note: Education history isn't as difficult, because you can include an Organization object
"alumniOf": [ {
"#type": "OrganizationRole",
"alumniOf": {
"#type": "CollegeOrUniversity",
"name": "City University of New York",
"sameAs": "https://en.wikipedia.org/wiki/City_University_of_New_York"
},
"startDate": "1990",
"endDate": "1992",
"roleName": "MBA"
}, {
"#type": "OrganizationRole",
"alumniOf": {
"#type": "CollegeOrUniversity",
"name": "University of California, Berkeley",
"sameAs": "https://en.wikipedia.org/wiki/University_of_California,_Berkeley"
},
"startDate": "1983",
"endDate": "1987",
"roleName": "BSc Psychology"
}
]
Ok, I know this hasn't been responded to in a while, but I have been looking at this question a lot because I'm trying to 'JSONize' my resume data :)
Here is the approach that I took for work history. I made my person and all of its attributes, then I have an occupation (my current occupation) and then I have previous occupations (past-selves, if you will). So having said that much, I can tell you that I put my work history in my alumniOf property.
According to schema.org, the alumniOf property is used to illustrate a person-organization relationship that has ended; I don't work at those places anymore.
Then when I 'instantiate' the organization objects, they can have an employee. That employee is 'my past self', who then has an occupation at that time working at xyz corp. That 'past-person' is the same person as my present person, which I then link using a format similar example 5 from https://schema.org/Book.
Take a look at my code below to get some clarification.
I hope this helps - if nothing else someone else can come along and tweak my response so that we could have something that will work for people when they google it.
{
"#context": "http://schema.org",
"#type": "Person",
"#id": "#john",
"name": "John Smith",
"address": {
"#type": "PostalAddress",
"addressCountry": "US",
"addressLocality": "Austin",
"addressRegion": "Florida",
"postalCode": "12345",
"streetAddress": "123 breeze way"
},
"email": "john#example.org",
"telephone": "1234567890",
"image": "",
"jobTitle": "Software Developer",
"description": "Blip about me...",
"contactPoint": [{
"#type": "ContactPoint",
"contactType": "LinkedIn",
"identifier": "johnsmith",
"image": "imageurl",
"url": "profileurl"
},
{
"#type": "ContactPoint",
"contactType": "GitHub",
"identifier": "johnsmith",
"image": "imageurl",
"url": "profileurl"
}
],
"url": "example.org",
"hasCredential": [{
"#type": "EducationalOccupationalCredential",
"aggregateRating": {
"#type": "aggregateRating",
"ratingValue": "3.51",
"name": "GPA"
},
"credentialCategory": "degree",
"educationalLevel": "Bachelors of Science",
"dateCreated": "2015-05",
"about": {
"#type": "EducationalOccupationalProgram",
"name": "Computer Engineering"
},
"recognizedBy": {
"#type": "CollegeOrUniversity",
"name": "Some Awesome University",
"sameAs": "urlgoeshere"
}
}],
"hasOccupation": {
"#type": "EmployeeRole",
"roleName": "role title goes here",
"startDate": "2015-06"
},
"worksFor": {
"#type": "Organization",
"name": "big company",
"sameAs": "urlgoeshere"
},
"award": [
"Organizational Achievement Awards Q3'17, Q2'19, Q3'19",
"Divisional Recognition Award Q1'19",
"Dean's List: Spring '12,'14; Fall '13",
"President's List: Spring '13; Fall '14",
"Eagle Scout Leadership Service Award 2011"
],
"alumniOf": [{
"#type": "Organization",
"name": "old workplace",
"sameAs": "urlgoeshere",
"employee": {
"#type": "Person",
"hasOccupation": {
"#type": "EmployeeRole",
"roleName": "Computer Consultant",
"startDate": "2012-08",
"endDate": "2015-05"
},
"sameAs": "#john"
}
},
{
"#type": "Organization",
"name": "another company",
"sameAs": "urlgoeshere",
"employee": {
"#type": "Person",
"hasOccupation": {
"#type": "EmployeeRole",
"roleName": "internship",
"startDate": "2014-05",
"endDate": "2014-08"
},
"sameAs": "#john"
}
}
]
}
The below for is for the exact same goal. Here you can find a standard for creating resume with json-ld standards. You can use the lab-web to create a sample resume, get output and then compare the jsonld fields.
Here is the link to github
https://github.com/Jsonldresume/
Lab-web is for creating the resume and you can export it in jsonld format. You can run the app demo to see it in action.
Skill is the schema and context definition for a resume
Resume repository is for sharing your resume with others.

aggregateRating within Review object

We're trying to use the aggregateRating tag but we're getting this warning in the SDTT:
The aggregateRating property inside a Review object applies to the review itself, as a creative work. Did you mean to use reviewRating instead.
We want to aggregate the reviews from all users, not use reviewRating (we already use that one for our own reviews).
Does anyone know how to fix this error?
JSON-LD (example page):
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "Review",
"name": "It",
"datePublished": "2017-09-06",
"description": "Based on Stephen King's 1986 novel, […]",
"url": "https://dev.commonsensemedia.org/movie-reviews/it",
"reviewBody": "Based on Stephen King's 1986 novel, […]",
"author": {
"#type": "Person",
"name": "Jeffrey M. Anderson",
"sameAs": "https://dev.commonsensemedia.org/users/jeffrey-m-anderson"
},
"itemReviewed": {
"#type": "Movie",
"name": "It",
"sameAs": "http://www.imdb.com/title/tt1396484/",
"datePublished": "2017-09-08",
"image": {
"#type": "ImageObject",
"url": "image.jpg"
},
"director": {
"#type": "Person",
"name": "Andres Muschietti"
},
"actor": [
{
"#type": "Person",
"name": "Bill Skarsg\u00e5rd"
},
{
"#type": "Person",
"name": "Jaeden Lieberher"
},
{
"#type": "Person",
"name": "Finn Wolfhard"
}
]
},
"publisher": {
"#type": "Organization",
"name": "Common Sense Media",
"sameAs": "https://www.commonsensemedia.org"
},
"reviewRating": {
"#type": "Rating",
"ratingValue": "4"
},
"aggregateRating": {
"#type": "AggregateRating",
"ratingValue": "4.04651",
"bestRating": 5,
"worstRating": 1,
"reviewCount": "43",
"name": "Parents say",
"description": "All parent member reviews for It"
}
}
</script>
When you add the aggregateRating property to the Review item, the aggregated rating is for the review, not for the reviewed item.
If the aggregated rating is for the reviewed item, you have to add the aggregateRating to this item (e.g., Movie).
If that is what you want, you can move the aggregateRating under Movie, e.g.:
{
"#context": "http://schema.org",
"#type": "Review",
"itemReviewed": {
"#type": "Movie",
"aggregateRating": {
"#type": "AggregateRating"
}
}
}

How to enable rich snippets using JSON-LD code for multi product pages?

I would like to make rich snippets for product pages appear in google SERPS. It's for a page that:
Contains multiple products that each have individual prices
Has an average aggregate rating
As far as I understand it's possible to add multiple products to one page in schema org using multiple offers. The problem is that I couldn't find the documentation on how to do that using JSON-LD. I've tried it myself in the code below but have no idea if this is correct. Can I just add offers like this or do I need to add them in a different way?
<script type="application/ld+json">
{
"#context": "http://schema.org/",
"#type": "Product",
"aggregateRating": {
"#type": "AggregateRating",
"ratingValue": "[rating variable]",
"reviewCount": "[count variable]"
},
"name": "[product name]",
"offers": {
"#type": "Offer",
"price": "[price of product]",
"priceCurrency": "[currency]"
},
"name": "[product name]",
"offers": {
"#type": "Offer",
"price": "[price of product]",
"priceCurrency": "[currency]"
},
"name": "[product name]",
"offers": {
"#type": "Offer",
"price": "[price of product]",
"priceCurrency": "[currency]"
},
}
</script>
just create an array of the offers.
<script type="application/ld+json">
{
"#context": "http://schema.org/",
"#type": "Product",
"name": "[name]",
"image": "[logo]",
"aggregateRating": {
"#type": "AggregateRating",
"ratingValue": "[rating],
"reviewCount": "[votes]"
},
"offers": [{
"#type": "Offer",
"priceCurrency": "[currency]",
"price": "[price]",
"category": {
"#type": "thing",
"name": "[name product]"
}
},{
"#type": "Offer",
"priceCurrency": "[currency]",
"price": "[price]",
"category": {
"#type": "thing",
"name": "[name product]"
}
},{
"#type": "Offer",
"priceCurrency": "[currency]",
"price": "[price]",
"Category": {
"#type": "thing",
"name": "[name product]"
}
}]
}
</script>