You embedded a video (YouTube, Vimeo, MP4) on an article page and added a VideoObject JSON-LD block. Rich Results Test reports “Valid” and shows the parsed preview. Weeks pass. Search Console Enhancements → Videos shows zero items, or shows the page as indexed but with no video appearance. Your URL never appears in Google’s video tab. Valid schema is necessary but not sufficient for video rich results. Google has separate eligibility requirements: a reachable thumbnail of usable resolution, a contentUrl or embedUrl that resolves to an actual video player (not a wrapping HTML page), ISO 8601 dates, and a publicly accessible video (no login wall, no region lock for googlebot). This article walks the five common failure modes with concrete diagnostics.
Identify which case you are in (10 seconds)
| Symptom | Most likely cause |
|---|---|
| Rich Results Test “Valid” but Search Console Enhancements shows zero items | Crawl-time issue: thumbnail or video URL not reachable by Googlebot |
| Rich Results Test reports “Missing field thumbnailUrl” | Required field missing |
contentUrl is set but Google still does not pick up the video | URL points to an HTML wrapper page, not a video file |
| Video is indexed but no thumbnail shows in SERP | Thumbnail under 1200x720, wrong aspect ratio, or unreachable |
| One specific video missing | That video is private / region-locked / behind a paywall |
Common causes, ranked by hit rate
1. contentUrl points to a page, not a video file
The most common mistake. contentUrl must be a direct URL to a video file (mp4, webm, mov) — not the URL of the page that contains a <video> tag.
{
"@context": "https://schema.org",
"@type": "VideoObject",
"contentUrl": "https://yourdomain.com/articles/how-to-foo/",
"embedUrl": "https://yourdomain.com/articles/how-to-foo/"
}
Both URLs above are wrong. They point at the wrapping article page. Googlebot fetches them, gets HTML back, sees no video file, and discards the VideoObject.
Fix: either link directly to the video file, or use embedUrl pointing at the player iframe URL:
{
"@type": "VideoObject",
"contentUrl": "https://cdn.yourdomain.com/videos/how-to-foo.mp4",
"embedUrl": "https://www.youtube.com/embed/VIDEO_ID"
}
For YouTube: embedUrl is https://www.youtube.com/embed/VIDEO_ID — note /embed/, not /watch?v=. For Vimeo: https://player.vimeo.com/video/VIDEO_ID.
2. Missing or low-resolution thumbnailUrl
Google requires thumbnailUrl and the image must be reachable by Googlebot, served over HTTPS, and ideally at least 1200x720 (16:9). A 320x180 thumbnail will validate in Rich Results Test but will not produce a SERP thumbnail.
{
"@type": "VideoObject",
"thumbnailUrl": [
"https://yourdomain.com/videos/foo-thumb-1200x720.jpg",
"https://yourdomain.com/videos/foo-thumb-1920x1080.jpg"
]
}
You can pass multiple thumbnail URLs as an array — Google picks the best one.
How to spot it:
curl -A "Googlebot/2.1 (+http://www.google.com/bot.html)" -I "https://yourdomain.com/videos/foo-thumb.jpg"
# Expect 200 + image/jpeg
identify https://yourdomain.com/videos/foo-thumb.jpg # ImageMagick — confirms dimensions
If status is 403/401/302, the thumbnail is gated. If dimensions are under 1200x720, re-export.
3. uploadDate not in ISO 8601 format
uploadDate must be a full ISO 8601 string with timezone. "2026-05-19" works but is borderline; "2026-05-19T00:00:00Z" or "2026-05-19T14:30:00-07:00" is what Google prefers.
{
"@type": "VideoObject",
"uploadDate": "2026-05-19T14:30:00-07:00"
}
Common mistake: emitting "5/19/2026" (US locale) or any localized date string with non-ASCII separators (e.g., dates formatted with Chinese or Japanese era characters). Both will fail.
4. Video gated — login wall, paywall, geo-block
If Googlebot cannot fetch the video (or its embed page), it cannot verify the video exists. Sites behind a paywall, Vimeo private videos, or region-locked content are excluded from video rich results.
How to spot it:
curl -A "Googlebot/2.1" -I "https://www.youtube.com/embed/VIDEO_ID"
# Expect 200; 302-to-login or 401 means gated
For YouTube unlisted videos: VideoObject works only if embedUrl is the public embed URL. Truly private videos cannot get video rich results.
Fix: for paywalled content, use paywalled content schema (isAccessibleForFree: false plus hasPart with cssSelector). Google has a separate program for paywalled video.
5. Multiple VideoObject blocks on one page conflict
A page with both a hero video and an inline embedded video may emit two VideoObject blocks. If both have the same name or contentUrl, Google treats it as duplicate / ambiguous and may pick neither.
Fix: one canonical VideoObject per page representing the primary video. If you genuinely have multiple distinct videos on one page, give each a unique name and contentUrl, and consider whether each should be on its own dedicated URL for indexing reasons.
A copy-ready VideoObject template
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "How to set up a self-hosted server in 10 minutes",
"description": "Step-by-step walkthrough covering hardware selection, OS install, and SSH hardening.",
"thumbnailUrl": [
"https://yourdomain.com/videos/server-setup-thumb-1200x720.jpg",
"https://yourdomain.com/videos/server-setup-thumb-1920x1080.jpg"
],
"uploadDate": "2026-05-19T14:30:00-07:00",
"duration": "PT10M30S",
"contentUrl": "https://cdn.yourdomain.com/videos/server-setup.mp4",
"embedUrl": "https://www.youtube.com/embed/VIDEO_ID",
"publisher": {
"@type": "Organization",
"name": "Site name",
"logo": {
"@type": "ImageObject",
"url": "https://yourdomain.com/logo.png"
}
},
"potentialAction": {
"@type": "SeekToAction",
"target": "https://yourdomain.com/videos/server-setup#t={seek_to_second_number}",
"startOffset-input": "required name=seek_to_second_number"
}
}
Note: duration uses ISO 8601 duration format. PT10M30S = 10 minutes 30 seconds. PT1H5M = 1 hour 5 minutes.
Shortest fix path
In hit-rate order:
- Make
embedUrlthe actual player URL (/embed/VIDEO_IDfor YouTube,/video/VIDEO_IDfor Vimeo) — fixes ~40% - Add or upgrade
thumbnailUrlto 1200x720+: fixes ~25% - Convert
uploadDateto ISO 8601 with timezone: fixes ~15% - Verify Googlebot can fetch thumbnail + embed URL with
curl -A "Googlebot/2.1": fixes ~15% - One canonical VideoObject per page: the remaining 5%
Prevention
- Build VideoObject emission into a shared video-embed component so every embedded video automatically gets schema. Manual JSON-LD blocks per page drift.
- Validate VideoObject required fields at build time. Fail the build if
name,description,thumbnailUrl,uploadDate, or one ofcontentUrl/embedUrlis missing. - Generate thumbnails at 1920x1080 source resolution; downscale to 1200x720 for the schema array.
- Run Rich Results Test on a canary video page after every framework upgrade.
- Track Search Console Enhancements → Videos weekly. A sudden drop = template regression.
FAQ
Q: Does YouTube embed automatically generate VideoObject for my page? A: No. YouTube emits VideoObject on its watch page (youtube.com/watch?v=…), not on your page. When you embed via iframe, your page has no schema unless you add it manually.
Q: Required fields for VideoObject?
A: name, description, thumbnailUrl, uploadDate, and one of contentUrl or embedUrl. Providing both is recommended for maximum compatibility.
Q: Rich Results Test shows “Valid” but no video tab listing weeks later. Why? A: Validation only checks schema syntax. Indexing requires Googlebot to actually crawl the embed/content URL and confirm a video exists. Check the thumbnail and embed URL are publicly fetchable. Also check that the surrounding article page is indexed at all (URL Inspection).
Q: My YouTube video shows up in Google’s video tab from the YouTube URL but not from my page. A: Expected. The YouTube watch page is its own canonical for that video. Your page can also rank for video, but only if the embed is set up correctly AND your page has unique surrounding content that adds value beyond the embed.
Q: Should I use contentUrl or embedUrl?
A: Both if possible. contentUrl (direct video file) is what Google prefers for video sitemap inclusion. embedUrl (player iframe URL) is what users actually see. Self-hosted videos: set both. YouTube embeds: only embedUrl is available; that is fine.
Q: My video is on a paywalled article. Can I still get video rich results?
A: Yes via the paywalled content schema (isAccessibleForFree: false). Google has a separate compliance program — register your site and follow the paywalled content guidelines.
Related articles
- Structured data rich results warning
- Structured data invalid after template change
- Article date JSON-LD mismatch
- Breadcrumb JSON-LD mismatch
- Website JSON-LD inconsistency
Tags: #SEO #Troubleshooting #Debug #Structured data #Video schema #JSON-LD