VideoObject Schema Not Recognized in Search Console

You added VideoObject JSON-LD for embedded videos but no video rich result, no video tab listing. Why.

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)

SymptomMost likely cause
Rich Results Test “Valid” but Search Console Enhancements shows zero itemsCrawl-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 videoURL points to an HTML wrapper page, not a video file
Video is indexed but no thumbnail shows in SERPThumbnail under 1200x720, wrong aspect ratio, or unreachable
One specific video missingThat 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:

  1. Make embedUrl the actual player URL (/embed/VIDEO_ID for YouTube, /video/VIDEO_ID for Vimeo) — fixes ~40%
  2. Add or upgrade thumbnailUrl to 1200x720+: fixes ~25%
  3. Convert uploadDate to ISO 8601 with timezone: fixes ~15%
  4. Verify Googlebot can fetch thumbnail + embed URL with curl -A "Googlebot/2.1": fixes ~15%
  5. 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 of contentUrl / embedUrl is 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.

Tags: #SEO #Troubleshooting #Debug #Structured data #Video schema #JSON-LD