VideoObject schema: required props and duration format
A page with an embedded video and no VideoObject markup, or markup missing thumbnailUrl, uploadDate or an ISO 8601 duration. squirrel checks both.
What VideoObject schema is
VideoObject is the schema.org type for a video. It names the video with name and description, points at a still with thumbnailUrl, dates it with uploadDate, and locates the file with contentUrl for the video itself or embedUrl for a player.
duration is typed as an ISO 8601 duration, which starts with P and puts a T before any time component: PT1H30M for ninety minutes, PT45S for forty-five seconds. A plain number of seconds or a 1:30:00 clock string is not valid. The markup describes a video present on the page, so it belongs on the watch page rather than on an index of videos.
What squirrel checks
The rule reads every script[type="application/ld+json"] on the page, flattens each one so a node nested in an @graph wrapper counts the same as a top-level node, and keeps the first VideoObject node from the last script that contains one, matching either a plain @type or an @type array. It also looks for a <video> element, or an <iframe> whose src contains youtube or vimeo. It emits one to three checks:
video-schema: with noVideoObjectnode and a video element present, it warns with the messagePage has video but no VideoObject schemaand the valueAdd schema for video rich results. With noVideoObjectnode and no video element it reports at info status with the messageNo VideoObject schema found. Either way no further checks run.video-required: warns with the messageVideoObject missing required propertiesand lists the missing names as items. The required set isname,description,thumbnailUrlanduploadDate. When all four are present it passes withVideoObject has required properties.video-recommended: emitted only when at least one ofduration,contentUrlandembedUrlis absent, at info status, with the messageVideoObject could include recommended properties.video-duration: emitted only whendurationis a string that does not begin withPT. It warns with the messageDuration should use ISO 8601 formatand the valueGot: <value>, expected: PT1H30M.
The duration check tests the PT prefix and nothing else, so PTbanana passes and a valid date-only duration such as P1D is reported as malformed. A duration given as a number rather than a string is not checked at all. Every property test is a truthiness test rather than a presence test, so a property present but empty, 0 or false counts as missing. A <video> element is detected whatever domain it plays from; only the iframe match is restricted to src values containing youtube or vimeo, so a third-party player under another domain does not count as video on the page.
How to fix it
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Setting up the build cache",
"description": "A six-minute walkthrough of the cache configuration.",
"thumbnailUrl": "https://example.com/thumbs/build-cache.jpg",
"uploadDate": "2026-03-14T09:30:00Z",
"duration": "PT6M12S",
"embedUrl": "https://www.youtube.com/embed/abc123"
}
</script>Put it in the <head> of the page the video plays on, and generate duration from the source file rather than typing it.
The common false positive is a video loaded by a script after page load. squirrel reads the HTML the server sent unless browser rendering is on, so the element is not there and the page reports No VideoObject schema found instead of warning about missing markup.
| Rule ID | schema/video |
| Category | Structured Data |
| Scope | Per-page |
| Severity | warning |
| Weight | 5/10 |
Enable / disable
Disable this rule
[rules]
disable = ["schema/video"]Disable all Structured Data rules
[rules]
disable = ["schema/*"]Enable only this rule
[rules]
enable = ["schema/video"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- video/video-schema: the Video category’s own view of the same markup.
- video/video-thumbnail: whether the thumbnail this markup points at is usable.
- video/video-accessible: captions and transcripts for the video itself.
- schema/json-ld-valid: whether the JSON-LD parses and passes schema.org validation at all.
Structured data findings ship in every audit next to the core SEO, performance and agent experience rules. See Fix SEO issues with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Structured Data section of the report. Each video page lists the properties it is missing. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.