VideoObject structured data is a block of JSON-LD that tells Google what a video on your page is: its name, thumbnail, upload date, length and where the file lives. Adding it takes ten minutes. Proving that Google actually read it and indexed the video takes longer, and that second part is where most pages fall down. This post covers both.
Key takeaways
- Google needs three properties at minimum:
name,thumbnailUrlanduploadDate. -
contentUrlorembedUrlis what lets Google fetch the video itself. Add at least one. - Valid markup is not the same as an indexed video. The video also has to be the main content of the page.
- Check in three places: the Rich Results Test, URL Inspection, and the Video indexing report.
Contents
- What does VideoObject markup look like?
- Which properties actually matter?
- How do you add key moments?
- How do you confirm Google read it?
- Why is my video not indexed?
- FAQ
What does VideoObject markup look like?
It is a JSON-LD script tag in the page head or body. Here is the shape I use for a product demo page:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Exporting a release clip from the CLI",
"description": "A two minute walkthrough of rendering a release clip from a local repo.",
"thumbnailUrl": ["https://example.com/media/release-clip-poster.jpg"],
"uploadDate": "2026-10-20T09:00:00-04:00",
"duration": "PT2M04S",
"contentUrl": "https://example.com/media/release-clip.mp4",
"embedUrl": "https://www.youtube.com/embed/VIDEO_ID"
}
</script>
Two details trip people up. duration uses ISO 8601, so two minutes and four seconds is PT2M04S, not 2:04. And uploadDate should carry a timezone offset. Without one, Google has to guess.
If you render pages with a framework, generate this block from the same data that renders the player. Hand-written JSON-LD drifts the moment someone swaps the video and forgets the markup.
Which properties actually matter?
Three are required, a few more change what Google can do with the video.
| Property | Required? | What it does |
|---|---|---|
name |
Yes | Title shown in results |
thumbnailUrl |
Yes | Image for the result; must be crawlable |
uploadDate |
Yes | When the video was first published |
description |
Recommended | Context for matching queries |
duration |
Recommended | Shown as a length badge |
contentUrl |
Recommended | Direct link to the video file |
embedUrl |
Recommended | Link to the player, such as a YouTube embed |
hasPart (Clip) |
Optional | Key moments with timestamps |
The thumbnail has to be reachable by Googlebot. If your media folder is blocked in robots.txt, or the image sits behind a signed URL that expires, the markup validates and the thumbnail still fails.
How do you add key moments?
Add hasPart with one Clip per section. Each clip gets a name, a start offset and an end offset in seconds, plus a URL that jumps to that time.
"hasPart": [
{
"@type": "Clip",
"name": "Pick the repo",
"startOffset": 0,
"endOffset": 35,
"url": "https://example.com/demo?t=0"
},
{
"@type": "Clip",
"name": "Render and export",
"startOffset": 35,
"endOffset": 124,
"url": "https://example.com/demo?t=35"
}
]
This only helps if your player honors the t parameter. Test the URLs by hand before shipping. If the video is on YouTube, chapters in the description usually do this job for you.
How do you confirm Google read it?
Run three checks, in this order:
- Rich Results Test. Paste the live URL. It should detect a Video item with no errors. Warnings about optional fields are fine.
- URL Inspection in Search Console. Request indexing, then check the "Video indexing" section once the page has been crawled.
- Video indexing report. This lists pages where Google found a video and whether it indexed it, with a reason when it didn't.
The first check only proves the syntax. The second and third tell you what Google decided.
Why is my video not indexed?
The most common reason I see is "Video isn't on a watch page". Google indexes videos for pages where the video is the main content. A demo clip in the hero of a feature page, surrounded by marketing copy, often gets labeled this way even with perfect markup.
Other reasons worth checking:
- The thumbnail URL returns an error or is blocked.
- The player loads only after a click or a consent banner, so Googlebot never sees a video element.
- The video is too small on the page or placed far below the fold.
The practical fix for product sites is a dedicated page per demo: one video, a short description, a transcript and the markup. I wrote up how that fits with getting product videos into Google rich results, including which pages deserve their own watch page.
At DemoVexa we render demo videos from a local codebase, so the script, timings and chapter names already exist as data. Feeding them into JSON-LD is a small step, and it is part of why I care about getting code-generated product demo videos indexed properly.
FAQ
Does VideoObject markup work for YouTube embeds?
Yes. Use embedUrl with the YouTube embed link. Google often finds YouTube videos without markup, but the markup ties the video to your page.
Is JSON-LD better than microdata for video?
Google accepts both. JSON-LD is easier to generate and keep in sync because it sits in one block instead of being spread across HTML attributes.
How long does video indexing take?
It varies by site and crawl frequency. Request indexing in URL Inspection and check the Video indexing report after the page is recrawled.
Do I need a separate thumbnail for the markup?
You need one crawlable image URL. Reusing the player's poster image works well and keeps the result consistent with what visitors see.
Baltej Singh is the founder of DemoVexa, a desktop app and CLI that turns a local codebase into narrated product demo videos. He writes from Delaware, USA.
Top comments (0)