What Is Multimodal Markup and How Do You Implement It in 2026?
A model can only quote what survives the conversion from HTML to text, and that conversion keeps your alt text, your caption and your transcript while throwing the pixels away. This page shows you exactly what to attach to an image, a video and an inline SVG so each one arrives at an answer engine as something readable.
Multimodal Markup (Alt text, captions, transcripts and media schema) is the collection of text representations you attach to non-text media so a machine can read it: the alt attribute, <figure> and <figcaption>, WebVTT caption tracks, an on-page transcript, <title> and <desc> inside inline SVG, and ImageObject and VideoObject structured data. It is not one specification: WHATWG HTML defines the elements, the W3C publishes WebVTT and the accessibility patterns, and schema.org (currently v30.0, released 19 March 2026) defines the media types. It exists because a retrieval pipeline that reduces your page to text keeps every one of those strings and discards the image bytes.
Why Multimodal Markup matters for AI visibility
There is a real difference between a model looking at an image and a crawler deciding what your page says. Current frontier models are genuinely multimodal and can read a chart when the image is handed to them in a prompt. The pipeline that builds a citation is a different operation: it fetches HTML, strips it to text or markdown, chunks it, and embeds it. In that pipeline an <img> collapses to its alt attribute and nothing else. Google says the same thing about its own indexing in plainer language: the image SEO documentation, last updated 2 March 2026, calls alt text "the most important attribute when it comes to providing more metadata for an image" and adds that Google "extracts information about the subject matter of the image from the content of the page, including captions and image titles".
That gives you a practical hierarchy, and it is worth being blunt about which layer does what. Alt text is the only thing every consumer sees, because it is the fallback baked into HTML itself, so it has to state what the image shows. The figcaption is ordinary body text: it stays next to the image in the reading order, it survives chunking with the image reference attached, and it is therefore the string most likely to be quoted back verbatim, so put the source, the date, the units and the sample size there. Surrounding context is what a chunker bundles with the image and what Google says it uses to work out subject matter, which is why an image dropped into an unrelated section earns nothing. Structured data does not usually become the sentence a model cites: ImageObject and VideoObject drive eligibility and entity resolution, the licensable badge, video rich results and key moments. Ship all four, but do not expect a schema description to rescue an image whose visible page says nothing about it.
Where the spec lives
Four primary sources and two vendor documents cover everything on this page. The vendor docs are the ones that change, so check their last-updated stamps before you copy anything.
- HTML Living Standard: the figure element - the normative content model. A figure is "flow content, optionally with a caption, that is self-contained", and the figcaption must be the first or last child, never in the middle.
- W3C WAI: Complex images - the two-part text alternative pattern for charts, diagrams and maps: a short identifier plus a full textual representation of the data. Reach for this whenever alt text alone cannot carry the numbers.
- WebVTT: The Web Video Text Tracks Format - Candidate Recommendation Draft of 20 May 2026. The file must start with the string WEBVTT, and cue timings use the format 00:11.000 followed by an arrow and 00:13.000.
- schema.org VideoObject - where
transcript,captionandembeddedTextCaptionare defined. Note that these are schema.org properties, not Google features, so read this alongside the Google page below. - Google Search Central: Video structured data - the only three required properties are
name,thumbnailUrlanduploadDate. Google recommendscontentUrloverembedUrl, and key moments need a video of at least 30 seconds. - Google Search Central: Image SEO best practices - alt text, descriptive filenames, placement near relevant text, and the supported formats list (BMP, GIF, JPEG, PNG, WebP, SVG and AVIF).
Three ways to implement Multimodal Markup
These are three different media types rather than three variations of one snippet, because the markup that makes each one readable is genuinely different. Start with the image if you publish articles carrying charts and photographs, the video if you host media yourself and want the spoken content quotable, and the SVG if your diagrams are drawn in code and currently reach a model as an undifferentiated pile of path data.
Informative image: figure, figcaption and ImageObject
Use this for any image that carries information the prose does not repeat: a chart, a screenshot, a labelled photograph. The pattern separates three jobs that are usually collapsed into one string, and it is the single highest-value change on most content sites.
<figure id="fig-flow-temp">
<img src="/img/heat-pump-flow-temperature-curve.png"
width="1600" height="900"
loading="lazy" decoding="async"
alt="Line chart: flow temperature falls from 52 C at minus 3 C outdoors to 32 C at 12 C outdoors.">
<figcaption>
Weather compensation curve measured on an 8.5 kW air source heat pump in
Sheffield, October 2025 to April 2026. Slope 0.6, no room thermostat override.
</figcaption>
</figure>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"@id": "https://example.com/guides/heat-pump-sizing/#article",
"headline": "How to size a heat pump for a 1930s terrace",
"image": {
"@type": "ImageObject",
"@id": "https://example.com/guides/heat-pump-sizing/#fig-flow-temp",
"contentUrl": "https://example.com/img/heat-pump-flow-temperature-curve.png",
"width": 1600,
"height": 900,
"caption": "Weather compensation curve measured on an 8.5 kW air source heat pump in Sheffield, October 2025 to April 2026.",
"creditText": "Example Energy field data",
"creator": { "@type": "Organization", "name": "Example Energy" },
"copyrightNotice": "Copyright 2026 Example Energy",
"license": "https://creativecommons.org/licenses/by/4.0/",
"acquireLicensePage": "https://example.com/licensing/",
"representativeOfPage": true
}
}
</script>
What this does: The alt text states the shape of the data, the figcaption supplies the equipment, the location, the date range and the setting, and the two do not overlap, so a text extraction of this page yields two distinct facts instead of one repeated one. The ImageObject is nested inside the article rather than floating free, so the image is bound to the entity it illustrates, and contentUrl plus one of creator, creditText, copyrightNotice or license is exactly what Google's image licence metadata requires.
Video watch page: caption track, in-DOM transcript and VideoObject
Use this on a dedicated watch page for self-hosted video. Video is the media type where the gap between what a human gets and what a model gets is widest, because nothing at all crosses over unless you write it down.
<video id="bleed" controls preload="metadata" width="1280" height="720"
poster="/img/bleeding-a-sealed-system-poster.jpg">
<source src="/media/bleeding-a-sealed-system.mp4" type="video/mp4">
<source src="/media/bleeding-a-sealed-system.webm" type="video/webm">
<track default kind="captions" srclang="en" label="English"
src="/media/bleeding-a-sealed-system.en.vtt">
<track kind="descriptions" srclang="en" label="English audio description"
src="/media/bleeding-a-sealed-system.en.desc.vtt">
</video>
<details class="transcript" open>
<summary>Full transcript</summary>
<p><b>00:00</b> Close both isolation valves either side of the circulating pump before you touch the bleed screw.</p>
<p><b>00:24</b> Fit a 5 mm bleed key to the radiator vent and turn it a quarter turn anticlockwise, no further.</p>
<p><b>01:07</b> Top the system back up to 1.2 bar on the filling loop once the last radiator runs quiet.</p>
</details>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Bleeding a sealed central heating system",
"description": "A four minute walkthrough of venting air from a pressurised heating system without losing system pressure.",
"thumbnailUrl": ["https://example.com/img/bleeding-a-sealed-system-poster.jpg"],
"uploadDate": "2026-06-11T09:00:00+01:00",
"duration": "PT4M12S",
"contentUrl": "https://example.com/media/bleeding-a-sealed-system.mp4",
"inLanguage": "en-GB",
"transcript": "Close both isolation valves either side of the circulating pump before you touch the bleed screw. Fit a 5 mm bleed key to the radiator vent and turn it a quarter turn anticlockwise, no further. Top the system back up to 1.2 bar on the filling loop once the last radiator runs quiet.",
"caption": {
"@type": "MediaObject",
"contentUrl": "https://example.com/media/bleeding-a-sealed-system.en.vtt",
"encodingFormat": "text/vtt",
"inLanguage": "en-GB"
}
}
</script>
What this does: The <details> transcript is the part that earns citations, because it is real text in the HTML source that an extractor keeps whether or not the element is expanded. The track element carries the same words as timed WebVTT for viewers and for any consumer that fetches the .vtt file, and the JSON-LD gives Google the three properties it actually requires (name, thumbnailUrl, uploadDate) plus contentUrl, which Google explicitly prefers over embedUrl.
Inline SVG diagram: title, desc and the numbers in a table
Use this for architecture diagrams, flow charts and data visualisations rendered as inline SVG. An SVG in the DOM looks readable and usually is not: the text extractor sees coordinates, and the <text> labels are fragments with no relationships between them.
<figure class="diagram">
<svg viewBox="0 0 520 140" width="520" height="140" role="img"
aria-labelledby="cachepath-title cachepath-desc"
xmlns="http://www.w3.org/2000/svg">
<title id="cachepath-title">Where requests to www.example.com are answered</title>
<desc id="cachepath-desc">Four stages left to right. The edge cache answers 82 percent of
requests at a median of 12 ms. 14 percent are rendered by the application server at 180 ms.
The remaining 4 percent reach the database at 240 ms.</desc>
<rect x="8" y="44" width="104" height="52" rx="8" fill="#1f2937"/>
<text x="60" y="75" text-anchor="middle" fill="#e5e7eb" font-size="13">Browser</text>
<rect x="144" y="44" width="104" height="52" rx="8" fill="#1f2937"/>
<text x="196" y="75" text-anchor="middle" fill="#e5e7eb" font-size="13">Edge cache</text>
<rect x="280" y="44" width="104" height="52" rx="8" fill="#1f2937"/>
<text x="332" y="75" text-anchor="middle" fill="#e5e7eb" font-size="13">App server</text>
<rect x="416" y="44" width="96" height="52" rx="8" fill="#1f2937"/>
<text x="464" y="75" text-anchor="middle" fill="#e5e7eb" font-size="13">Database</text>
<path d="M112 70 H144 M248 70 H280 M384 70 H416" stroke="#34d399" stroke-width="2"/>
</svg>
<details class="diagram-data">
<summary>Data behind this diagram</summary>
<table>
<caption>Requests answered at each stage, week commencing 17 August 2026</caption>
<thead><tr><th scope="col">Stage</th><th scope="col">Share</th><th scope="col">Median latency</th></tr></thead>
<tbody>
<tr><th scope="row">Edge cache</th><td>82%</td><td>12 ms</td></tr>
<tr><th scope="row">App server</th><td>14%</td><td>180 ms</td></tr>
<tr><th scope="row">Database</th><td>4%</td><td>240 ms</td></tr>
</tbody>
</table>
</details>
<figcaption>Request path and hit rates for www.example.com, week commencing 17 August 2026.</figcaption>
</figure>
What this does: role="img" plus aria-labelledby pointing at both the <title> and the <desc> is the pattern that behaves consistently across screen readers, and it collapses the SVG into a single labelled object so the loose <text> fragments stop being announced separately. The table is the part a model can actually cite, because the relationships between stage, share and latency are only recoverable from structure, not from a picture. The figcaption is last, which the HTML standard allows: it must be the first or last child of the figure and never in between.
Implementation guidelines
These are the failures that show up on real sites once the markup is in place.
- Alt describes, caption contextualises, and they must not be the same string. If the
altand the<figcaption>carry identical text, a screen reader announces it twice and a text extractor recovers one fact where it could have had two. Alt says what the image shows, the caption says where it came from and what it means. - An empty alt is a decision, a missing alt is a bug. Write
alt=""on decorative images so they are explicitly skipped, and never omit the attribute. Glippy, browsers and assistive technology all treat an absent attribute differently from a deliberately empty one. - The transcript has to be in the HTML source, not fetched on click. A
<details>element works because its contents are in the served markup whether or not it is open. A transcript that a script loads after a user interaction is invisible to every crawler and to most agent browsers. - Serve WebVTT same-origin, with the right MIME type. The
srcof a<track>must be same-origin unless the parent media element carriescrossorigin, and the file must be served astext/vttstarting with the literal string WEBVTT. Get either wrong and the track fails silently with no console error in some browsers. - role="img" on an SVG hides everything inside it. Once you set that role, the child
<text>nodes stop being exposed to assistive technology, so the<desc>has to carry every number and label you care about. Do not assume the visible labels are doing the work. - Structured data must agree with the visible page. The
contentUrlon anImageObjecthas to be the same file the<img>loads, and Google requires the marked-up video to be present and playable on the page. Mismatched or stale media URLs are the most common reason a video rich result never appears. - Audit the extracted text, not the rendered page. Run the URL through an HTML-to-markdown converter, or through Glippy, and read what is left. If a chart contributes nothing to that output, it will contribute nothing to a citation, no matter how good it looks in a browser.
Do this, not that
Do
- Write alt text that states what the image shows in roughly 80 to 140 characters, and let the figcaption carry the source, date, units and sample size.
- Ship a WebVTT track with
kind="captions",srclangandlabelset, plusdefaulton the one track you want enabled. - Put the full transcript in the served HTML, inside a container whose class or id contains the word transcript.
- Give every informative inline SVG a
<title>first, a<desc>second, and wire both up withrole="img"andaria-labelledby.
Do not
- Do not write alt text like
image1.png,photoorchart; Glippy scores anything under five characters, a bare generic word, or a filename as generic alt. - Do not put the same sentence in
altand<figcaption>, and do not open the alt with "image of" or "picture of". - Do not wrap decorative icons and logos in
<figure>: an uncaptioned figure drags your caption ratio down and adds nothing an extractor can use. - Do not point
thumbnailUrlorcontentUrlat a signed or expiring CDN URL; both have to stay fetchable long after the page is published.
How Glippy checks this
Glippy scores this as category 16, Multimodal Content, at a category weight of 0.5, and it runs six sub-checks over the rendered DOM and the parsed JSON-LD. Image Alt Quality (25 points) counts an alt as generic if it is under five characters, is the bare word image, photo, picture or img, matches a pattern like img_12, or ends in a file extension, and it passes only when 80 percent or more of the images clear that bar. Figure Captions (20 points) is the ratio of figure figcaption to figure. Video Accessibility (20 points) passes if it finds a <track> with kind="captions" or kind="subtitles" inside a <video>, or any element whose class or id contains transcript, or a .video-description, and it counts YouTube, Vimeo and generic player iframes as video. SVG Descriptions (15 points) counts an SVG as described if it has a <title> or <desc> child, an aria-label, or role="img". Image Schema (10 points) walks the entire JSON-LD graph looking for an ImageObject at any depth, including one nested inside an Article or Product. Media Variety (10 points) rewards three or more of images, video, SVG, audio and canvas on the same page.
Two results confuse people. If a page has content images but no <figure> element anywhere, Figure Captions returns an informational result worth zero of its twenty points, which is the largest silent loss in the category; before it decides that, Glippy filters out decorative images using empty alt, role="presentation", aria-hidden, class hints such as icon, logo, avatar and banner, an ancestor of aside, header, nav, footer or button, and any declared dimension of 100 pixels or less. And SVG Descriptions is deliberately lenient: a bare role="img" passes it, so a green tick there does not mean a model can read your diagram. Add the <title> and <desc> anyway. Full per-check detail is on the Multimodal Content Checker page.
Check your Multimodal Markup setup
Glippy runs 240+ checks across 16 categories on any page, including Multimodal Content (category 16). No sign-up required.
Frequently asked questions
Both happen, but not in the same operation. A frontier model can read an image when the image is handed to it in a prompt, which is what occurs when a user uploads a screenshot or an agent takes a page capture. The retrieval pipeline that decides whether to cite your page is different: it fetches HTML, reduces it to text, and in that reduction an <img> is represented by its alt attribute and its surrounding text. Write for the pipeline, because that is the one that produces citations.
Alt text is the replacement for the image: it states what is depicted, for someone or something that will never see the pixels. The figcaption is ordinary visible body text that a sighted reader also gets, so it carries the things a picture cannot say by itself: the source, the date range, the units, the equipment, the sample size. Because the caption is normal prose in the reading order, it is the string most likely to be quoted verbatim in a generated answer. Never make the two identical.
Schema.org does define transcript on VideoObject, along with caption and embeddedTextCaption, and they are valid as of schema.org v30.0. Google's video structured data documentation does not list transcript among its required or recommended properties, so adding it will not on its own earn a video rich result. Include it anyway for consumers that read raw schema.org, but rely on the visible on-page transcript as the thing that actually gets quoted.
Put a <title> as the first child of the <svg> and a <desc> immediately after it, give both an id, and reference them from role="img" and aria-labelledby on the SVG element. Be aware that role="img" makes the SVG's children presentational, so any label sitting in a <text> node stops being exposed and the <desc> must carry the full description. For a chart, follow the W3C WAI complex images pattern as well and publish the underlying numbers as a real HTML table next to the diagram.
Reviewed against the primary sources on . These standards move quickly, so check the linked specs before you ship.