Start here: would Google call this a watch page?
Only if watching one video is the main reason someone comes to the page. Google's term is a watch page, and it gives examples such as a video landing page or an episode player page. A blog post with a video embedded beside the text is not one, and neither is a review with a trailer. Those pages can still appear as ordinary results.
Take a church that keeps its services in a library. Here is how its pages sort out, on our reading of the rule:
| Page on the site | Watch page? | What to do |
|---|---|---|
| /sermons/ grid of 200 thumbnails | No | Leave it out of the file, and link each video from it |
| /news/ article with a clip halfway down | No | Leave it out and let it rank as an article |
| /sermons/hope-in-hard-times/ with the player on top and a short summary | Yes | This page goes in the file |
Each watch page also needs a title and description of its own. If your library has no page per video yet, build those first.
Sitemap, media RSS or markup: which one do you need?
A sitemap and VideoObject markup together, for most sites. Google recommends video sitemaps and also supports media RSS, which is an RSS feed with tags that describe video. Whatever you use, make them agree: Google asks for the same thumbnail URL across every metadata source.
| Method | Good for | Watch out for |
|---|---|---|
| Video sitemap | A whole library at once, on your own domain | Up to 50,000 URLs or 50 MB per file. Split larger ones |
| Media RSS (mRSS) | A feed you already have, submitted like a sitemap | Titles stop at 100 characters. Feeds usually list only recent items, and Search Console has a status reading "MRSS failure; try using schema.org instead" |
| VideoObject markup | Each watch page, and it stays with the page | It needs a template change, and dates should carry a time zone |
Why the library's feed is an ingredient, not the finished file
Because the page in each entry has to be yours. The video on demand library gives every file a player, an embed code and a link, and lets you set a poster image. It also includes MRSS feeds for Google. A media RSS feed normally carries the thumbnail, title and player address. Open the feed before you submit anything, though, and look at the page address in each entry. If it points at a share page on the host and not at your own watch page, the entry won't describe your site. Google only lets one sitemap list URLs from several sites when you have verified ownership of every one of them.
So treat it as a data source. These are the media RSS names from the specification, and where each value belongs.
| Sitemap tag | Comes from | Rule to respect |
|---|---|---|
loc | Your site, never the feed | Your watch page |
video:thumbnail_loc | media:thumbnail url | Reachable by Googlebot, at a stable URL, 60×30 pixels at the least |
video:title | media:title | Should match the title on the page |
video:description | media:description | 2,048 characters at most |
video:player_loc | media:player url | Must differ from loc. For an embed, this is the iframe's address |
video:content_loc | media:content url | The file itself, and Google's preferred way to fetch it. Must differ from loc |
video:duration | media:content duration | 1 to 28,800 seconds |
Our church's entry comes out like this. The video is on the host's address and the page on the church's domain, the same split Google shows in its own example.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url>
<loc>https://www.example.org/sermons/hope-in-hard-times/</loc>
<video:video>
<video:thumbnail_loc>https://media.example.net/posters/4471.jpg</video:thumbnail_loc>
<video:title>Hope in Hard Times</video:title>
<video:description>Sunday sermon on Psalm 46, with the reading and closing prayer.</video:description>
<video:content_loc>https://media.example.net/files/4471.mp4</video:content_loc>
<video:player_loc>https://media.example.net/embed/4471</video:player_loc>
<video:duration>2460</video:duration>
</video:video>
</url>
</urlset>
For more than a handful, let a script do the copying. Save the script below as build.py. Keep a two-column file, pages.csv, with no heading row: on each line, the media:player url copied exactly from the feed, then your watch page. Run python3 build.py FEED_URL pages.csv video-sitemap.xml.
It needs nothing beyond Python and ignores videos you haven't given a page. If any page in pages.csv is missing from the feed or has no thumbnail or title, it stops and keeps the old sitemap, so a short feed can't quietly drop older videos. A line that isn't exactly two columns stops it too. Add a line to pages.csv and rerun it after each upload. If your library is bigger than the feed, this script can't hold all of it.
The script reads RSS. If the top tag of your feed is urlset, it is already in sitemap form, so use an RSS feed here, or copy it and change each loc to your own page.
import csv, os, sys, urllib.request
import xml.etree.ElementTree as ET
from xml.sax.saxutils import escape
M = './/{http://search.yahoo.com/mrss/}'
feed, pages, out = sys.argv[1:4]
with open(pages, encoding='utf-8-sig', newline='') as f:
page = dict(r for r in csv.reader(f) if r)
root = ET.fromstring(urllib.request.urlopen(feed, timeout=30).read())
def tag(name, value):
return '<video:%s>%s</video:%s>' % (name, escape(value), name)
rows = {}
for it in root.iter('item'):
pl, th = it.find(M + 'player'), it.find(M + 'thumbnail')
url = pl.get('url') if pl is not None else None
title = it.findtext(M + 'title') or it.findtext('title')
if url in page and th is not None and title:
text = it.findtext(M + 'description') or title
rows[url] = '<url><loc>%s</loc><video:video>%s%s%s%s</video:video></url>' % (
escape(page[url]), tag('thumbnail_loc', th.get('url')), tag('title', title),
tag('description', text[:2048]), tag('player_loc', url))
if not rows or len(rows) < len(page):
sys.exit('STOP - %d of %d pages usable, old file kept' % (len(rows), len(page)))
with open(out + '.tmp', 'w', encoding='utf-8') as f:
f.write('<?xml version="1.0" encoding="UTF-8"?><urlset '
'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video='
'"http://www.google.com/schemas/sitemap-video/1.1">')
f.write(''.join(rows.values()) + '</urlset>')
os.replace(out + '.tmp', out)
print(len(rows), 'written')
The script writes player_loc only, which is the safe minimum for an embed. Add content_loc and duration by hand or extend it once you've read the next section. Use python on Windows.
Four ways an embed quietly loses the video
How these meet our own features is our reading, so check each one on a real page.
- Expiring links. Google wants the video at a stable URL, and a library on signed links hands out addresses that expire. Signed links cover the whole library, so a library you want indexed has to run without them. Leave private videos out of the file.
- Rules that shut Googlebot out. Website and country rules can turn away a crawler as easily as a stranger. Google says to check with your host that it may fetch the file, and to keep thumbnails and video bytes out of any robots.txt block, on both hosts.
- A click to load the player. Many sites show a poster and load the iframe only on a click, to keep the page fast. Google says not to rely on swiping, clicking or typing to load a video, so the player must be in the rendered page. Our notes on embedding a player cover the rest of what breaks on a page.
- The same video in two places. With a third-party embed, Google may index the video on your page and on the host's own page too, so link to and share your watch page, not the host's. Each library file also has a CDN link and a server link: pick one and use the same address in every metadata source.
Add the markup while you're in the template
Google requires name, thumbnailUrl and uploadDate. Give the date a time zone, or Google uses Googlebot's. Add embedUrl for the player address from your embed code, plus contentUrl if you can offer a stable file address, and write duration in ISO 8601, so 41 minutes is PT41M.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Hope in Hard Times",
"description": "Sunday sermon on Psalm 46, with the reading and closing prayer.",
"thumbnailUrl": "https://media.example.net/posters/4471.jpg",
"uploadDate": "2026-10-18T11:30:00-04:00",
"duration": "PT41M",
"embedUrl": "https://media.example.net/embed/4471"
}
</script>
Submit it and read what Search Console says back
- Put the file at your site's root and add a line such as
Sitemap: https://www.example.org/video-sitemap.xmlto robots.txt. - Submit it in the Sitemaps report in Search Console, which shows when Google read it and any processing errors.
- Paste one watch page into URL Inspection. A Video indexing section appears only if Google detected a video on that page. If it's missing, look at the rendered HTML for your iframe.
- Give it time, then open the Video indexing report. It lists indexed pages with a video, and a reason for those without.
- After a fix, press Validate fix once and leave it. Google says validation typically takes up to about two weeks.
| Reason in the report | Likely cause with an embed | Fix |
|---|---|---|
| Video isn't on a watch page | A list page or article is in your file | Give the video its own page, or drop the entry |
| Cannot determine video position and size | The player loads only after a click on a poster, or is hidden when the page renders | Load the player with the page, at its real size |
| No thumbnail URL provided | The file has no poster | Add a poster, then rerun the script |
| Video not found on host service | The address has expired or changed, or the host turned Googlebot away | Use a stable address that lets Googlebot in |
The Performance report can also be filtered to videos. Judge the work there, not by the file being accepted.
Questions people ask
- Do I need a sitemap if my pages already have VideoObject markup?
- Not strictly, since Google can find videos from the page itself. A sitemap is still worth having for a large library or for pages that are hard to reach by links.
- Is a video sitemap generator worth using?
- Only if it lets you set the watch page for each video. Some crawl a site and list every page that has a player, which puts article and list pages in the file. A short script built on your feed, like the one above, keeps the choice in your hands.
- Can I submit a media RSS feed as it stands?
- Yes, if every page it names is on your own site. Feeds can be tested, submitted and updated just like sitemaps. If the feed sits on the host's address, reference it from your own robots.txt, since you can't verify the host's site in Search Console. If the entries point at a host's page, build your own file.