Overview

Video can appear in the web SERP video carousel, the Google Videos vertical, and YouTube search. Google indexes a video only when it is embedded on a watch page where viewing is the page’s primary purpose, and that page itself must be indexed. A video tucked beside an article is usually not indexed as a video, even if it plays fine for users.

Build a dedicated watch page

Give each video its own page, with the player, the transcript, and the markup. A YouTube embed can be indexed as a video on your page under the same condition. Google discovers videos through <video>, <embed>, <iframe>, and <object> elements, and thumbnails must sit at a stable URL.

Emit VideoObject JSON-LD with the required fields

Put the block in the same HTML response as the player. Google requires name, thumbnailUrl, and uploadDate (ISO 8601 with a timezone offset). It recommends contentUrl (preferred) or embedUrl, description, duration, and creator. A missing required field makes the video ineligible; Search Console’s Video indexing report shows why.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "How to ship a static site to Cloudflare Pages",
  "description": "Twelve-minute walkthrough from git push to live URL.",
  "thumbnailUrl": "https://example.com/thumbs/cf-pages.jpg",
  "uploadDate": "2026-05-10T09:00:00-07:00",
  "duration": "PT12M14S",
  "contentUrl": "https://example.com/videos/cf-pages.mp4",
  "embedUrl": "https://www.youtube.com/embed/abc123"
}
</script>

Use one thumbnail URL in the markup, Open Graph, and the player. See schema-markup-deep for the field reference.

Put the transcript in the page body

Keep the full transcript inline below the player, in the initial HTML, under an <h2>Transcript</h2>. A transcript behind a JavaScript toggle may be missed by crawlers that do not render, including many AI crawlers (javascript-seo). Time-stamp it every 30 to 60 seconds so it doubles as a chapter index, and it serves screen-reader users when the player is inaccessible.

Host on YouTube and your own domain when traffic matters

YouTube wins on discovery and the owned domain wins on attribution and on-site engagement.

  • YouTube hosts the canonical embed and accrues YouTube search traffic.
  • The owned domain hosts a <video> with controls, poster, and a captions <track>; this page is the canonical for web ranking.
  • Both copies share the same transcript and markup, with different embedUrl and contentUrl values.

Ship captions as a WebVTT track

Provide a .vtt file through a <track kind="captions"> element with the right srclang. Edit auto-generated captions before publishing, since errors teach crawlers the wrong terms. Burned-in captions are unreadable to crawlers and screen readers.

<video controls poster="/thumbs/cf-pages.jpg">
  <source src="/videos/cf-pages.mp4" type="video/mp4" />
  <track kind="captions" src="/captions/cf-pages.en.vtt" srclang="en" label="English" default />
</video>

Add a video sitemap entry

A video sitemap states what the video is. Extend the main sitemap with the video namespace or ship a separate file. Required per entry: video:thumbnail_loc, video:title, video:description (up to 2,048 characters, matching the page), and one of video:content_loc or video:player_loc. video:duration runs 1 to 28,800 seconds.

<url>
  <loc>https://example.com/cf-pages</loc>
  <video:video>
    <video:thumbnail_loc>https://example.com/thumbs/cf-pages.jpg</video:thumbnail_loc>
    <video:title>How to ship a static site to Cloudflare Pages</video:title>
    <video:description>Walkthrough from git push to live URL.</video:description>
    <video:content_loc>https://example.com/videos/cf-pages.mp4</video:content_loc>
    <video:duration>734</video:duration>
  </video:video>
</url>

Reference the sitemap from robots.txt; see sitemaps-deep.

Avoid these video errors

  • A thumbnail in JSON-LD that differs from the Open Graph image and player poster.
  • A transcript hidden in a JavaScript modal.
  • A missing uploadDate.
  • Unreviewed auto-generated or auto-translated captions.
  • An embed that is incidental to the page text, so it is never indexed as a video.