image-seo
Improves how search engines find and rank your images by fixing alt text, filenames, and formats.
Installation
Paste this into Claude Code, Cursor, or any agent that can run commands.
SKILL.mdShow the author's original SKILL.md
---
name: image-seo
description: Optimise images for search, accessibility, performance and AI multimodal retrieval — alt text, filenames, formats, sizing, lazy loading and image sitemaps. Use whenever the user mentions image SEO, alt text, alt tags, image optimization, Google Images, image search, WebP or AVIF, responsive images, srcset, lazy loading, image sitemaps, or images slowing down a page. Also use when auditing a content-heavy or ecommerce site.
---
# Image SEO
Three separate wins, usually treated as one: traffic from image search, faster pages, and content that multimodal systems can actually interpret. Alt text serves accessibility first, and the SEO benefit is a byproduct of doing it properly rather than a reason to do it badly.
## Alt text
Write it for someone who can't see the image. That constraint produces good SEO alt text automatically, and every attempt to reverse the priority produces worse text for both.
| Context | Good alt | Why |
|---|---|---|
| Product photo | `Blue running shoe, side view, showing the mesh upper and heel counter` | Describes what's visible |
| Chart | `Bar chart: organic sessions rose from 12,000 in January to 31,000 in August 2026` | The data, not "a chart" |
| Screenshot | `Search Console Pages report showing 340 URLs excluded as crawled, currently not indexed` | What's on screen |
| Decorative | `alt=""` | Empty, so screen readers skip it |
| Image inside a link | `Pricing page` | Describes the destination, not the picture |
| Logo | `Example` or `Example home` | The brand name |
Rules:
- **Describe, don't keyword-stuff.** `alt="running shoes cheap running shoes best running shoes"` fails accessibility and reads as spam.
- **Skip "image of" and "picture of".** Assistive technology already announces it's an image.
- **Under about 125 characters.** Longer gets truncated by some screen readers. If the image genuinely needs more, put the explanation in the surrounding text or a caption.
- **Empty alt for decorative images**, not a missing alt attribute. Missing means the screen reader reads the filename, which is worse.
- **Include the key term only if it's genuinely what's shown.**
Captions are read more than body text and are underused. If an image needs explaining, a visible caption serves everyone.
## Filenames and URLs
```
IMG_20260907_142233.jpg → blue-running-shoe-mesh-upper.jpg
DSC_0042.png → search-console-pages-report.png
```
Lowercase, hyphenated, descriptive, no spaces or underscores. It's a small signal, and it's free at upload time and expensive to fix later.
Keep image URLs stable. Renaming images resets whatever image-search equity they had.
## Formats
| Format | Use for | Note |
|---|---|---|
| **AVIF** | Photos, the default now | Best compression, universal modern support |
| **WebP** | Photos, fallback for older clients | Good compression, wider legacy support |
| **SVG** | Logos, icons, diagrams | Vector, tiny, scales. Sanitise user-uploaded SVGs |
| **PNG** | Only when transparency and lossless are both needed | Large |
| **JPEG** | Legacy fallback | Superseded by the two above |
| **GIF** | Never | Use a video or an animated WebP |
```html
<picture>
<source srcset="/img/hero.avif" type="image/avif">
<source srcset="/img/hero.webp" type="image/webp">
<img src="/img/hero.jpg" alt="..." width="1200" height="630">
</picture>
```
## Sizing and responsive delivery
The most common cause of a failing mobile LCP is a desktop-sized hero served to a phone.
```html
<img
src="/img/shoe-800.avif"
srcset="/img/shoe-400.avif 400w, /img/shoe-800.avif 800w, /img/shoe-1600.avif 1600w"
sizes="(max-width: 640px) 100vw, 50vw"
width="800" height="600"
alt="Blue running shoe, side view"
loading="lazy"
decoding="async">
```
- **Always set `width` and `height`.** The browser reserves the space from the aspect ratio, which prevents layout shift. This single attribute pair fixes most CLS.
- **`sizes` must reflect the actual CSS layout.** Getting it wrong means the browser picks the wrong candidate and the whole `srcset` is wasted.
- **Serve images at the size they're displayed**, at 1x and 2x. Nothing larger.
## Lazy loading, and the exception
```html
<!-- Below the fold -->
<img loading="lazy" decoding="async" ...>
<!-- The LCP image — never lazy -->
<img fetchpriority="high" ...>
<link rel="preload" as="image" href="/img/hero.avif" fetchpriority="high">
```
Lazy-loading the hero image is the most common self-inflicted Core Web Vitals failure. It adds a full round trip to LCP because the browser won't start fetching until layout runs. Lazy-load everything below the fold and nothing above it.
Also: the LCP image must be a real `<img>` in the HTML. A CSS `background-image` is invisible to the preload scanner, and one injected by JavaScript is discovered even later.
## Image sitemaps
Worth it for ecommerce, publishers and anywhere image search sends traffic. Either extend the existing sitemap or ship a separate one.
```xml
<url>
<loc>https://example.com/p/blue-runner</loc>
<image:image>
<image:loc>https://example.com/img/blue-runner-side.avif</image:loc>
<image:title>Blue Runner, side view</image:title>
</image:image>
</url>
```
And check that images aren't blocked. `Disallow: /assets/` or `/_next/image` in robots.txt keeps images out of image search entirely, and also breaks Google's rendering of the page. It's a common accidental block.
```bash
curl -s https://example.com/robots.txt | grep -iE "disallow.*(img|image|asset|static|media|_next)"
```
## Images and AI systems
Multimodal models can interpret images, but retrieval pipelines still lean heavily on text. Two practical consequences:
- **Never put facts only in an image.** Pricing tables, spec sheets, comparison charts and infographics rendered as images are invisible to text-based retrieval. Whatever the graphic says, say it in the HTML too — as a real table, a list, or prose near the image.
- **Alt text and captions are the text layer for an image.** Good ones make the image's content retrievable. This is a genuine reason to write them well beyond accessibility.
Original images are also one of the few remaining easy edges. Google's generative features surface images, and most sites use the same stock photography as their competitors. A real screenshot, a real photograph of the actual product, or a diagram you drew is content nobody else has.
## Auditing a site
```bash
# Images missing alt attributes entirely
curl -s https://example.com/page \
| grep -oE '<img[^>]*>' \
| grep -v 'alt=' \
| head -20
# Images without width/height (CLS risk)
curl -s https://example.com/page \
| grep -oE '<img[^>]*>' \
| grep -vE 'width=.*height=|height=.*width=' \
| head -20
# Oversized images
curl -s -o /dev/null -w '%{size_download} bytes\n' https://example.com/img/hero.jpg
```
Anything over about 200 KB for a content image, or 400 KB for a hero, needs compression or a better format.
## Don't do these
- **Don't keyword-stuff alt text.** Fails accessibility, reads as spam.
- **Don't leave alt missing on decorative images.** Use `alt=""`.
- **Don't use text in images** for anything that matters. Not indexable, not accessible, not translatable, and it doesn't scale.
- **Don't upload originals straight from a camera.** A 6 MB JPEG on a product page is a conversion problem before it's an SEO one.
- **Don't lazy-load above the fold.**
- **Don't use stock photography for a review or roundup.** It's the clearest signal that nobody handled the product. See `best-of-listicle-pages`.
## Related skills
`core-web-vitals`, `technical-seo-audit`, `ecommerce-seo`, `nextjs-seo`, `schema-markup`, `video-seo`
Mirrored from the author's public source. Install counts from the open skills registry.