XooCode(){

Video Schema Generator

Fill out a form. Get valid VideoObject JSON-LD.

A form-driven builder for schema.org VideoObject markup with a live JSON-LD preview that updates as you type. Handles the contentUrl / embedUrl distinction, ISO 8601 duration assembly from minutes and seconds, repeatable Clip rows for key moments in Full coverage mode, plus optional BroadcastEvent for the live badge and LearningResource dual-typing for educational content. Everything runs in your browser, nothing is sent to XooCode.

Video form

Title of the video. Emits as VideoObject.name.

What the video is about. Google truncates at ~160 chars in the SERP.

Absolute URL to a thumbnail image. Google requires at least 60x30px.

ISO 8601 date when the video was first published.

Direct URL to the video file (.mp4, .webm). Preferred by Google.

URL of the embeddable player (YouTube, Vimeo embed URL).

Combined with seconds to produce an ISO 8601 duration.

e.g., 4 min 50 sec emits PT4M50S.

Live JSON-LD output

schema.org/VideoObject
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "name": "How XooTee Classics are screen-printed",
  "description": "Watch the full screen-printing process at Xoo Code Shop Dunmore. From selecting the blank shirt to quality checking the finished print, this walkthrough covers every step of how each XooTee Classic gets its water-based design.",
  "thumbnailUrl": "https://xoocode.com/media/xootee-print-thumb.jpg",
  "uploadDate": "2025-09-15",
  "contentUrl": "https://xoocode.com/media/xootee-print.mp4",
  "embedUrl": "https://www.youtube.com/embed/xootee-print-2025",
  "duration": "PT4M50S"
}
</script>

Updates as you type. Empty fields are omitted from the output. Click the copy icon above to copy the full <script> tag ready for pasting into your HTML head.

How to use the generator

Two-pane layout: form on the left, live JSON-LD preview on the right. Type into any field and the preview updates. When you’re done, click the copy icon in the preview header and paste the <script> block into your page’s <head>.

  1. 1

    Start from the seed or start blank

    The form loads with the XooTee screen-printing walkthrough video prefilled, so you can see a realistic output on first paint. Click Load XooTee example to reset to this seed at any time. To start from scratch, clear the fields manually.
  2. 2

    Pick your coverage mode

    The Coverage dropdown has two settings. Essential shows the seven fields Google requires or recommends for a basic video rich result. Full keeps all of that and adds publisher, language, transcript, expiry, view count, content rating, key-moment Clips, and the BroadcastEvent / LearningResource composition blocks.
  3. 3

    Fill in the video metadata

    Name and description are required. The thumbnailUrl must be a direct link to an image file, not to a page that contains the video. Duration is two numeric fields (minutes + seconds) that the generator assembles into the ISO 8601 format Google expects (e.g., PT4M50S).
  4. 4

    Add Clips for key moments (Full mode)

    In Full mode, each Clip row becomes a hasPart entry with a name, a start offset, and an end offset (all in seconds from the start of the video). These render as the key-moments carousel under the video rich result in Google. Click Add clip to add more rows, use the arrows to reorder.
  5. 5

    Attach composition blocks (optional)

    In Full mode, two optional blocks appear below the Clips section. BroadcastEvent enables the live badge on the video rich result (toggle isLiveBroadcast and set the start/end dates). LearningResource promotes the output type to ["VideoObject", "LearningResource"] for Google’s learning video enrichments.

contentUrl vs embedUrl

Google accepts either contentUrl or embedUrl and recommends providing both when possible. They are not interchangeable.

contentUrl is a direct link to the video file: an .mp4, .webm, or .ogg URL that Google can fetch and crawl directly. Self-hosted videos, CDN links, and cloud storage URLs go here. Google prefers this field because it can extract duration and generate thumbnails from the file itself without rendering a player.

embedUrl is the URL of an embeddable player: a YouTube /embed/ URL, a Vimeo player URL, or a Wistia embed endpoint. This is what you get from the “Share > Embed” dialog on most video platforms. Google can still index the video from this, but it has to render the player to do so.

ISO 8601 duration and the form's input trick

The duration property uses ISO 8601 duration format, which looks like this:

PT4M50S  =  4 minutes, 50 seconds
PT12M    =  12 minutes, 0 seconds
PT45S    =  0 minutes, 45 seconds
PT1H30M  =  1 hour, 30 minutes
PT90M    =  90 minutes (valid, same as PT1H30M)

The leading PT stands for “period of time.” The M after the T is minutes, not months (months would appear before the T). Developers frequently write "4:50" or "290" instead, both of which Google silently drops. The duration badge disappears from the rich result and the video may lose its thumbnail card entirely.

The generator sidesteps this by exposing two numeric fields (minutes and seconds) and assembling the ISO string for you. Type 4 and 50 and the output emits PT4M50S. You never have to remember the format.

Key moments and the Clip pattern

Key moments are the clickable timestamps that appear in a horizontal strip below a video rich result in Google Search. Each one is a Clip object nested inside the VideoObject’s hasPart array. A Clip has four properties: name (the label), startOffset (seconds from the start), endOffset (seconds from the start), and an optional url (a deep link that jumps to that point in the video).

Google also supports a second mechanism for key moments: SeekToAction on the video URL, which tells the crawler how to construct a timestamp link dynamically. This is the pattern YouTube uses internally. For most publishers, the explicit Clip approach is simpler and more predictable. The generator only emits Clip objects; if you need SeekToAction, write it by hand.

Offsets are always in seconds from the start of the video, not timestamps. startOffset: 90 means 1 minute and 30 seconds into the video.startOffset: "1:30" is invalid because the value must be a number, not a string. The form enforces this with a numeric input.

Live badge and learning video

Two optional composition blocks in Full mode unlock distinct Google features that are separate from the base video rich result.

The BroadcastEvent block attaches a publication object with isLiveBroadcast, startDate, and endDate. When isLiveBroadcast is true and the current time falls inside the start/end window, Google renders a red “LIVE” badge on the video thumbnail in search results. After the broadcast window ends, the badge disappears and the video appears as a regular recording. This is useful for webinars, live product demos, and streamed events.

The LearningResource block toggles the output @type from "VideoObject" to ["VideoObject", "LearningResource"] and exposes learningResourceType and educationalAlignment. Google uses this dual-typing for the learning video enrichment: educational carousel cards, Study Guides, and Practice Problems that appear in search results for learning queries. Only enable this for genuinely educational or instructional content.

What this generator isn't

The Video Schema Generator covers the full VideoObject vocabulary from Essential through BroadcastEvent and LearningResource. Here is what it does not try to do.

It IS a VideoObject JSON-LD builder

Full VideoObject vocabulary: name, URLs, thumbnail, duration, Clip key moments, BroadcastEvent live badge, LearningResource dual-typing, publisher, view count, transcript, expiry, content rating, and region restrictions.

It is NOT a video player

This generates structured data for search engines and AI crawlers. It doesn't play, embed, or transcode video files. For the player, that's YouTube, Vimeo, or your CDN.

It IS Clip-aware for key moments

Repeatable Clip rows with startOffset and endOffset in seconds. Reorder, add, remove. The output emits valid hasPart arrays that trigger the key-moments carousel in Google.

It is NOT a duration format reference

The form assembles ISO 8601 from minutes + seconds so you never type it raw. But if you need the full ISO 8601 spec for edge cases (hours, fractional seconds), consult the spec directly.

It IS live-badge aware

The BroadcastEvent block outputs publication with isLiveBroadcast, startDate, and endDate. When the broadcast window is active, Google renders the red LIVE badge on the thumbnail.

It is NOT a SeekToAction builder

Key moments use the explicit Clip pattern. If you need SeekToAction (the YouTube-internal approach), write it by hand. Most publishers don't.

Authoritative sources behind the VideoObject vocabulary

The generator’s behaviour is sourced from primary documentation. These are the documents to consult when you need to verify anything the tool produces.

  • schema.org/VideoObject. The canonical vocabulary definition. VideoObject inherits from MediaObject which inherits from CreativeWork which inherits from Thing.
  • schema.org/Clip. The type each key-moment row emits as. Carries startOffset, endOffset, name, and the rarely-used clipNumber property.
  • Google VideoObject structured data documentation. The current required and recommended property lists, the key-moments guidance, and the BroadcastEvent live badge policy.
  • ISO 8601 Durations (Wikipedia). The format specification for the duration property. Covers the PT prefix, unit letters, and edge cases like fractional seconds.
  • Google Rich Results Test. Run your generator output through this to confirm the markup is valid and that the video thumbnail renders as expected.