Back

Blog details

Video SEO: How to Get Video Content Indexed by Google

AIOZ Network
8 min readSeptember 24, 2026
aioz-streamguide

Video SEO is the work of getting your videos found, indexed and shown in Google's video results. Google doesn't watch your video to understand it. It reads the watch page, VideoObject structured data, a video sitemap and a crawlable thumbnail, so those are what you optimize.

AIOZ Stream doesn't generate that markup for you, but its video API returns every field you need to build it. This guide covers the Google requirements first, then shows how each one maps to AIOZ Stream fields.

TL;DR:

  • Google indexes a video only when it sits on an indexed watch page, isn't hidden, and has a valid thumbnail at a stable URL.
  • VideoObject markup needs name, thumbnailUrl and uploadDate. Google recommends contentUrl (or embedUrl), description and duration on top.
  • A video sitemap helps discovery. Clip or SeekToAction markup enables key moments, and Search Console's Video indexing report tells you which videos made it in.
  • AIOZ Stream returns title, description, created_at, duration, a thumbnail URL and playback URLs for every video. You convert duration from seconds to ISO 8601 before you use it.

Updated Nov 4, 2026: new sections on watch pages, video sitemaps, key moments with Clip markup, thumbnail rules and Search Console checks, plus a labelled field-mapping diagram and a tested duration converter.

How does Google index video content?

Google first has to find the video, and according to Google's video SEO best practices, it looks for a <video>, <embed>, <iframe> or <object> element in the rendered HTML. If you inject the player with JavaScript, check that it shows up in the URL Inspection tool, and don't make it wait for a click or swipe.

Then Google decides whether the video can be indexed: the page that embeds it must be indexed and performing well in Search, and the video must be visible on that page with a valid thumbnail at a stable URL. If any of these fail, your page can still rank as a text result, but the video won't get video features.

The page Google wants is a watch page, where watching one video is the main reason you'd visit. A product page with a demo clip or a blog post that reviews an embedded video doesn't count. Give each watch page its own title and description, and use the same video on other pages if you like.

Diagram mapping AIOZ Stream video API fields to VideoObject properties, video sitemap tags and Clip markup
Where each AIOZ Stream field ends up: VideoObject, the video sitemap and Clip markup for key moments.

Video SEO also sits inside a wider accessibility topic, and our guide to what WCAG requires for video covers captions and transcripts, which help both viewers and search engines. If a term in this post is new, the video streaming glossary defines it.

Which VideoObject fields does Google require?

Google's VideoObject reference lists three required properties: name, thumbnailUrl and uploadDate in ISO 8601 format. Without them, Google may not be able to extract any information about your video.

The recommended list is longer, and you should start with contentUrl, the URL of the video bytes, which Google calls the most effective way to fetch your file; if you can't, give embedUrl for the player instead. Add description and duration as well, plus expires only when a video is due to go away.

The AIOZ Stream get-video-detail response has a field for each of these. title, description, created_at and duration sit on the video object. The assets object holds thumbnail_url, hls_url, mp4_url, hls_player_url and dash_player_url, and the AIOZ Stream developer guide shows how to call it. Here is the template we'd render into each watch page:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "{{ video.title }}",
  "description": "{{ video.description }}",
  "thumbnailUrl": "{{ video.assets.thumbnail_url }}",
  "uploadDate": "{{ video.created_at }}",
  "duration": "{{ video.duration | iso8601 }}",
  "contentUrl": "{{ video.assets.hls_url }}",
  "embedUrl": "{{ video.assets.hls_player_url }}"
}
</script>

For contentUrl, Google lists M3U8 among its supported file types, so the hls_url playlist works. Keep each name, description and thumbnail unique per video, because Google asks for unique values on every video on your site.

The duration gotcha

The docs' example response returns duration as seconds, 283.492426, while Google expects an ISO 8601 duration such as PT4M43S. If you pass the raw number through, nothing throws an error and the markup quietly fails validation, so convert it with a small helper:

function toIsoDuration(seconds) {
  const s = Math.round(seconds);
  const h = Math.floor(s / 3600);
  const m = Math.floor((s % 3600) / 60);
  return `PT${h ? h + 'H' : ''}${m ? m + 'M' : ''}${s % 60}S`;
}
console.log(toIsoDuration(283.492426)); // PT4M43S
console.log(toIsoDuration(3725.2));     // PT1H2M5S

We ran this with Node.js 22 on Nov 4, 2026, and the comments show the real output. The sitemap tag works the other way: <video:duration> takes whole seconds from 1 to 28,800, so you only round the AIOZ value there.

Video sitemaps: what to include

A video sitemap tells Google where your watch pages and their videos are. You can add video tags to your existing sitemap or keep a separate one, and Google's video sitemap reference covers every tag. The required ones are <video:thumbnail_loc>, <video:title>, <video:description> (up to 2,048 characters), and either <video:content_loc> or <video:player_loc>.

Every URL you list must be reachable by Googlebot without a login, robots.txt block or firewall, and you shouldn't list a video that's only a small addendum to the page. One entry built from AIOZ Stream fields looks like this:

<url>
  <loc>https://example.com/watch/product-tour</loc>
  <video:video>
    <video:thumbnail_loc>{{ video.assets.thumbnail_url }}</video:thumbnail_loc>
    <video:title>{{ video.title }}</video:title>
    <video:description>{{ video.description }}</video:description>
    <video:player_loc>{{ video.assets.hls_player_url }}</video:player_loc>
    <video:duration>{{ video.duration | round }}</video:duration>
  </video:video>
</url>

Sitemaps and structured data do different jobs, and you'll want both. The sitemap helps Google find the watch page, and the markup on the page tells Google what the video is once it gets there.

Key moments with Clip and SeekToAction

Key moments let searchers jump to a segment of your video, like chapters in a book. Google tries to detect segments on its own, but it gives priority to the ones you set, and for a video embedded on your own site you have two options.

Clip markup lists each segment yourself, with a name, a startOffset in seconds and a url that points to that moment on the same page path. SeekToAction instead tells Google how your timestamp URLs work, and Google picks the moments. Clip works in every language Google Search supports, while SeekToAction covers 12 languages, including English, Spanish and Japanese.

If you already store chapters on AIOZ Stream, you have the data. The chapter API keeps one WebVTT file per language, and each cue's start time and text become one Clip:

"hasPart": [
  {
    "@type": "Clip",
    "name": "Upload and encoding",
    "startOffset": 0,
    "endOffset": 95,
    "url": "https://example.com/watch/product-tour?t=0"
  },
  {
    "@type": "Clip",
    "name": "Playback and analytics",
    "startOffset": 95,
    "endOffset": 283,
    "url": "https://example.com/watch/product-tour?t=95"
  }
]

Your watch page then has to read the t parameter and start playback at that second. Our comparison of the media chapter and media transcript APIs shows how the chapter files are structured.

Thumbnails that Google can use

Every video needs a valid thumbnail to get video features, and Google accepts BMP, GIF, JPEG, PNG, WebP, SVG and AVIF, at a minimum of 60x30 pixels, and larger is better. The file must be reachable by Googlebot and Googlebot Images at a stable URL.

If you set the thumbnail in several places, such as the poster attribute, the sitemap and thumbnailUrl, use the same URL in all of them. On AIOZ Stream, assets.thumbnail_url is built from the video ID, and you can replace the image with a PNG or JPG through the upload-thumbnail endpoint. Pick a frame that says what the video is about, because it's the first thing a searcher sees.

How do you check that Google indexed your videos?

Search Console gives you three reports for this, and you should check them after your first deploy and after any template change:

  • Video indexing report: shows how many indexed watch pages have an indexed video, and why the others didn't make it, for example "Video isn't on a watch page". After a fix, you can start validation, which Google says typically takes up to about two weeks.
  • Video rich result report: lists errors and warnings in your VideoObject markup across the whole site, so one broken template shows up as many pages.
  • Performance report: filter by the Videos search appearance to see clicks and impressions from video results.

Before you deploy, paste a watch page into Google's Rich Results Test to validate the markup. After you deploy, run URL Inspection on one page to confirm Google sees the player in the rendered HTML.

How AIOZ Stream handles it

Everything you need comes from one call, and the request below is copied from the Video API reference; we didn't run it here, and you'd swap in your own video ID and token:

curl --location 'https://api.aiozstream.network/api/media/video_id' \
--header 'authorization: Bearer your_access_token_here'

The response carries the fields from the template above, plus is_public, because only public videos belong in your sitemap and markup. Captions help search too, because they give crawlers real text from the video, and our captions and transcripts developer guide shows how to add them. To embed the player on your watch page, follow how to embed the AIOZ Stream player.

What the docs don't cover yet:

  • generated VideoObject markup, video sitemaps or oEmbed;
  • a start-time URL option for the embed player, which Clip URLs rely on, so test your seek handling before you ship Clip markup.

For the full list of video fields and endpoints, start with the AIOZ Stream Video API docs.

Frequently Asked Questions

What are the required fields for VideoObject schema?
Google requires name, thumbnailUrl and uploadDate in ISO 8601 format, and it recommends contentUrl or embedUrl, description and duration for richer results.

Does AIOZ Stream automatically generate VideoObject schema markup?
No. Its docs don't mention structured data, JSON-LD, oEmbed or sitemap generation, so you build the markup from the API fields.

Which AIOZ Stream API fields map to VideoObject properties?
title to name, description to description, assets.thumbnail_url to thumbnailUrl, created_at to uploadDate, duration to duration after conversion, assets.hls_url to contentUrl, and assets.hls_player_url to embedUrl.

Why would my VideoObject markup fail validation with every field filled in?
The duration is the usual cause. AIOZ Stream returns seconds as a number such as 283.492426, and Google needs ISO 8601 such as PT4M43S.

Do I need both a video sitemap and structured data?
Yes, in most cases. The sitemap helps Google find the watch page, and the structured data tells Google what the video is once it's there.

How do I get key moments for my videos?
Add Clip markup with a name, start offset and timestamp URL for each segment, or SeekToAction markup that tells Google how your timestamp URLs work.

How do I know if Google indexed my video?
Open the Video indexing report in Search Console. It lists watch pages with an indexed video and the reason each other video wasn't indexed.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

What Is Video Encoding? Codecs, Containers and Bitrate

Video encoding compresses raw video with a codec, then a container packages it for playback. See how codecs, containers, bitrate and rate control fit together.

aioz-streamguide
8 min readNovember 05, 2026
blog thumbnail

Video Streaming Protocols: HLS, DASH, WebRTC, RTMP and SRT

Video streaming protocols move video from encoder to viewer. See how RTMP, SRT, HLS, DASH and WebRTC differ in latency, transport and where each one fits.

aioz-streamguide
7 min readNovember 04, 2026
blog thumbnail

What Is Decentralized Live Streaming and How Does It Work?

Decentralized live streaming sends a real-time broadcast through independently run nodes instead of one company's servers. Here's how each stage of it works.

aioz-streamguide
6 min readNovember 03, 2026
blog thumbnail

Video Streaming Glossary: Codecs, Protocols and Delivery A-Z

A video streaming glossary of 114 terms, from AAC and ABR to WebRTC and Widevine, each defined in plain English with sources and links to the deep posts.

aioz-stream
23 min readOctober 31, 2026
blog thumbnail

Monitor Livestream Health With Bitrate, FPS and Viewer Count

Read the AIOZ Stream Statistics panel: bitrate in and out, FPS in and out and current viewers, plus the documented rules for each and what the docs leave out.

aioz-streamguide
6 min readOctober 30, 2026
blog thumbnail

How to Embed a Livestream on Your Website (Link or iFrame)

Embed an AIOZ Stream livestream with the Share button's iframe or send the Public Playback URL as a link. Covers API fields, public access limits and doc gaps.

aioz-streamguide
6 min readOctober 27, 2026