Video Schema Markup — VideoObject JSON-LD for Google
VideoObject tells Google the title, thumbnail, date, and file of the video on a watch page. Google requires three properties and supports key moments and the LIVE badge.
Generate VideoObject JSON-LDWhy video markup doesn't show up
- The markup is on a page that isn’t indexed, or that isn’t a watch page for the video. Google needs the watch page indexed first.
- embedUrl or contentUrl points at the page the video is on, not the player or the file.
- The thumbnail URL expires or is blocked by robots.txt, so Google can’t fetch it.
- Key moment clips have no url that starts the video at that time.
- SeekToAction uses query-input, but Google requires startOffset-input.
How SwiftSchema helps
The generator covers Google’s three required properties plus description, duration, contentUrl, embedUrl, and the creator.
It builds key moments as Clip items (name, start time, and clip URL) or as a SeekToAction with the startOffset-input Google requires, and adds a BroadcastEvent for livestreams.
What is VideoObject structured data?
VideoObject is the schema.org type for a video file. On the page where people watch a video, it gives Google the video's title, thumbnail, upload date, length, and the URL of the file or player.
Google says it tries to understand videos automatically, but markup lets you "influence the information that's shown in video results, such as the description, thumbnail URL, upload date, and duration." Videos can appear in the main search results, Video mode, Google Images, and Google Discover.
Required properties
| Property | What Google requires |
|---|---|
name | The video's title, unique for each video on your site. |
thumbnailUrl | One or more URLs of the video's thumbnail image. See the thumbnail rules below. |
uploadDate | When the video was first published, in ISO 8601. Google recommends a timezone, such as 2026-10-14T08:00:00-04:00. |
Recommended properties
| Property | Notes |
|---|---|
description | Unique for each video. Google ignores HTML tags in it. |
contentUrl | The URL of the video file itself, in a supported format such as MP4, WebM, or M3U8. Google says this is the most effective way for it to fetch your video. |
embedUrl | The URL of the player, usually the src of the iframe or embed element. Use it when contentUrl isn't available. Never the page the video is on. |
duration | ISO 8601, such as PT3M12S. |
creator (or author) | A Person or Organization with name and a url that identifies them. |
expires | When the video stops being available. Leave it out if it doesn't expire. |
hasPart | Clip items for key moments (below). |
interactionStatistic | An InteractionCounter with interactionType (WatchAction, LikeAction, CommentAction, or ShareAction) and userInteractionCount. |
publication | A BroadcastEvent for the LIVE badge (below). |
regionsAllowed or ineligibleRegion | Country codes where the video is or isn't available. Add whichever fits. |
publisher is a valid schema.org property on VideoObject, but Google's video documentation reads creator or author for who made the video.
Before markup: can Google index the video?
Google's video best practices list what a video needs before structured data can help:
- The watch page is indexed, and "performing well in Search." An indexed page doesn't guarantee an indexed video.
- The video is embedded on the watch page, not hidden behind other elements, and doesn't need the user to swipe, click, or type to load.
- A valid thumbnail at a stable URL: BMP, GIF, JPEG, PNG, WebP, SVG, or AVIF, at least 60x30 pixels, not blocked by robots.txt or a login.
- A supported file type, such as MP4, MOV, WebM, or M3U8. Data URLs don't work.
- Behind a paywall? Add paywalled content markup so Google can still find the video.
Key moments: Clip or SeekToAction
Key moments let people jump to parts of a video from Search. Google may find them automatically. To set them yourself, use one of two methods:
- Clip (in
hasPart): you list each segment with aname, astartOffsetin seconds, and aurlthat starts the video at that point, plus an optionalendOffset. No two clips on the same video may share a start time. Works in every language Google Search supports. - SeekToAction (in
potentialAction): you give atargetURL with{seek_to_second_number}where the timestamp goes, and"startOffset-input": "required name=seek_to_second_number". Google then finds the moments itself. Supported in 12 languages, including English and Spanish.
Google says to use Clip instead of SeekToAction if you prefer to mark key moments yourself. Both need a video of at least 30 seconds that can be deep-linked to a point other than the start, on a page where people can watch it. For a YouTube video, put timestamps in the YouTube description instead. To opt out of key moments entirely, use the nosnippet meta tag.
Livestreams and the LIVE badge
Add publication with a BroadcastEvent: isLiveBroadcast set to true, a startDate, and an endDate. If you don't know when the stream will end, give an estimate. Once it's over, the endDate must show when it actually ended.
Google asks you to call the Indexing API when the stream goes live, when it stops and the markup has the endDate, and whenever the markup changes. The Indexing API only supports livestream videos.
How to build it here
- 01
Enter the video title, a description, and a thumbnail URL that won’t expire.
- 02
Set the upload date and, if you know it, the duration in ISO 8601 (PT3M12S).
- 03
Add the video file URL as Content URL, the player URL as Embed URL, or both.
- 04
Add who made the video under Creator.
- 05
For key moments, add clips with a name, start time, and clip URL, or a SeekToAction template.
- 06
For a livestream, tick Live Broadcast and set the start and end times.
- 07
Copy the JSON-LD into the watch page, then test it in Google’s Rich Results Test.
Ready to build the markup?
One VideoObject per video, on its watch page.
The generator emits name, description, thumbnailUrl, uploadDate, duration, contentUrl, embedUrl, creator, hasPart clips, a SeekToAction potentialAction, and a BroadcastEvent publication. Empty fields are left out. The upload date and the live times have no timezone; add one such as -04:00 before you publish.
Common mistakes
embedUrlset to the page URL. It must be the player's URL.contentUrlmust be the file.- An expiring thumbnail URL from a CDN. Google needs one stable thumbnail URL per video, the same in your sitemap and markup.
- No dedicated watch page. Google's video features need a page whose main purpose is that one video.
- Clips without a
url, or two clips with the same start time. query-inputin SeekToAction. Google requiresstartOffset-input.- A
descriptioncopied across every video. Google asks for unique text innameanddescription.
Required properties
namethumbnailUrluploadDate
Recommended properties
descriptioncontentUrlembedUrl (if no contentUrl)durationcreator (or author)expireshasPart (Clip, for key moments)potentialAction (SeekToAction, for key moments)publication (BroadcastEvent, for the LIVE badge)interactionStatisticregionsAllowed or ineligibleRegion
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "How to Add Product Structured Data in 3 Minutes",
"description": "A walkthrough of adding Product JSON-LD to a store page and testing it in Google's Rich Results Test.",
"thumbnailUrl": [
"https://www.example.com/thumbs/product-jsonld-1x1.jpg",
"https://www.example.com/thumbs/product-jsonld-4x3.jpg",
"https://www.example.com/thumbs/product-jsonld-16x9.jpg"
],
"uploadDate": "2026-10-14T08:00:00-04:00",
"duration": "PT3M12S",
"contentUrl": "https://media.example.com/video/product-jsonld.mp4",
"embedUrl": "https://www.example.com/embed/product-jsonld",
"creator": {
"@type": "Organization",
"name": "Northstar Analytics",
"url": "https://www.example.com"
},
"interactionStatistic": {
"@type": "InteractionCounter",
"interactionType": {
"@type": "WatchAction"
},
"userInteractionCount": 4821
}
}{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "How to Add Product Structured Data in 3 Minutes",
"thumbnailUrl": "https://www.example.com/thumbs/product-jsonld-16x9.jpg",
"uploadDate": "2026-10-14T08:00:00-04:00",
"contentUrl": "https://media.example.com/video/product-jsonld.mp4",
"hasPart": [
{
"@type": "Clip",
"name": "Write the Product JSON-LD",
"startOffset": 15,
"endOffset": 95,
"url": "https://www.example.com/videos/product-jsonld?t=15"
},
{
"@type": "Clip",
"name": "Test it in the Rich Results Test",
"startOffset": 95,
"endOffset": 192,
"url": "https://www.example.com/videos/product-jsonld?t=95"
}
]
}{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "How to Add Product Structured Data in 3 Minutes",
"thumbnailUrl": "https://www.example.com/thumbs/product-jsonld-16x9.jpg",
"uploadDate": "2026-10-14T08:00:00-04:00",
"contentUrl": "https://media.example.com/video/product-jsonld.mp4",
"potentialAction": {
"@type": "SeekToAction",
"target": "https://www.example.com/videos/product-jsonld?t={seek_to_second_number}",
"startOffset-input": "required name=seek_to_second_number"
}
}{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Structured Data Office Hours, Live",
"description": "Live Q&A on schema markup and Google rich results.",
"thumbnailUrl": "https://www.example.com/thumbs/office-hours-16x9.jpg",
"uploadDate": "2026-10-20T12:00:00-04:00",
"embedUrl": "https://www.example.com/embed/office-hours",
"publication": {
"@type": "BroadcastEvent",
"isLiveBroadcast": true,
"startDate": "2026-10-20T12:00:00-04:00",
"endDate": "2026-10-20T13:00:00-04:00"
}
}FAQs
Which VideoObject properties does Google require?ShowHide
Three: name, thumbnailUrl, and uploadDate. Google recommends description, contentUrl or embedUrl, duration, creator, and the others listed on this page. Without the required properties, Google says it may not be able to extract any information about the video.
What's the difference between contentUrl and embedUrl?ShowHide
contentUrl is the URL of the video file itself, such as an MP4. embedUrl is the URL of the video player, usually the src of the iframe or embed element. Neither should be the page the video is on. Google says contentUrl is the most effective way for it to fetch your video, and embedUrl is the alternative.
How do I get key moments for my video?ShowHide
Either list each segment yourself with Clip (name, startOffset in seconds, and a url that starts the video at that point), or use SeekToAction to tell Google how your timestamp URLs work so it can find key moments itself. The video must be at least 30 seconds long and support deep links to a point in the video. For YouTube videos, timestamps in the YouTube description work instead.
How do I get the LIVE badge?ShowHide
Add publication with a BroadcastEvent that has isLiveBroadcast true, startDate, and endDate (an estimate is fine before the stream ends). Google asks you to call the Indexing API when the stream starts, when it ends, and when the markup changes.
Does VideoObject markup guarantee a video result?ShowHide
No. The watch page must be indexed and performing well in Search before its video is considered, the video must be embedded on that page and not hidden, and it needs a valid thumbnail at a stable URL. Google also doesn't guarantee any feature that uses structured data.
What format does uploadDate need?ShowHide
ISO 8601, such as 2026-10-14 or 2026-10-14T08:00:00-04:00. Google recommends including a timezone; without one, it uses Googlebot's timezone.