---
title: "Image SEO: formats, sizing, lazy-loading, alt text - Serpwise"
description: "Modern image practice for SEO: WebP/AVIF, responsive srcset, native lazy-loading, alt text that earns image search traffic, and the byte budgets that matter."
url: "https://serpwise.ai/learn/image-seo/"
source: "https://serpwise.ai/learn/image-seo/"
---
[← Back to Learn](/learn/)

Images & Media Info

# Image SEO: formats, sizing, lazy-loading, alt text

Modern image practice for SEO: WebP/AVIF, responsive srcset, native lazy-loading, alt text that earns image search traffic, and the byte budgets that matter.

Images are often a third or more of a page’s weight, the LCP element on most templates, and a meaningful source of organic traffic via Google Images. They’re also the easiest performance win on most sites - the gap between a 1.5 MB hero PNG and a 120 KB WebP is enormous, requires no application logic changes, and survives every redesign.

## Why it matters

Three concrete impacts:

1. **Performance.** Hero images are the LCP element on most templates. A slow hero image drops LCP into “needs improvement” territory regardless of how fast the rest of the page is.
2. **Image search traffic.** Google Images is one of the largest discovery channels - alt text and filename hygiene are the difference between ranking for “knee-length wool coat” and ranking for nothing.
3. **Accessibility.** Alt text is required for screen readers. The cost of doing it well for SEO is zero; the cost of doing it badly is a real accessibility failure.

## How to detect it

```
# Quick weight audit - sum image bytes on a page
curl -s https://example.com/some/page \
  | grep -oE 'src="[^"]+\.(jpg|jpeg|png|gif|webp|avif)[^"]*"' \
  | sed 's/src="//;s/"$//' \
  | while read url; do
      curl -sI "$url" | grep -i content-length
    done
```

PageSpeed Insights → Opportunities → “Properly size images” and “Serve images in next-gen formats” surface the worst offenders with exact byte savings.

For alt text audits:

```
curl -s https://example.com/some/page | grep -oE '<img[^>]*>' | grep -v 'alt='
```

Every `<img>` should have an `alt` attribute. `alt=""` is valid for purely decorative images; missing `alt` is a bug.

## The fix

### Modern formats - WebP and AVIF

WebP saves ~25-35% over JPEG at the same visual quality. AVIF saves another ~20% on top of WebP but encodes slowly and isn’t supported in some legacy browsers. The pattern: WebP with JPEG fallback covers &gt;97% of traffic.

```
<picture>
  <source srcset="/photo.avif" type="image/avif" />
  <source srcset="/photo.webp" type="image/webp" />
  <img src="/photo.jpg" alt="…" width="1600" height="900" />
</picture>
```

### Responsive images - `srcset` and `sizes`

Send the right pixel dimensions for the device:

```
<img
  src="/photo-800.webp"
  srcset="/photo-400.webp 400w,
          /photo-800.webp 800w,
          /photo-1600.webp 1600w,
          /photo-3200.webp 3200w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="…"
  width="800"
  height="450"
/>
```

`sizes` tells the browser how wide the image will display at each breakpoint; the browser picks the smallest candidate from `srcset` that fits.

### Lazy-loading - native only

```
<img src="/photo.webp" loading="lazy" alt="…" width="800" height="600" />
```

`loading="lazy"` is supported in every current browser. Don’t use a JS-based lazy-loading library - the native attribute is faster and doesn’t run on the main thread.

**Exception**: the LCP image. Setting `loading="lazy"` on the hero delays its load and tanks LCP. Use `loading="eager"` (the default) plus `fetchpriority="high"` on the LCP image:

```
<img src="/hero.webp" fetchpriority="high" alt="…" width="1600" height="900" />
```

### Alt text - write for the search query, not the image

Bad: `alt="image1.jpg"`, `alt="photo"`, `alt="banner"`.

Good: `alt="Knee-length wool overcoat in charcoal, front view"`.

Rules:

- Describe what’s in the image and what’s relevant. Don’t write “image of” or “photo of” - screen readers already announce that.
- 8-15 words is typical. Longer is fine if the image is detailed and central to the page.
- Don’t keyword-stuff. Google’s image alt analysis is dense and stuffed alt text is detected.
- `alt=""` (empty) is correct for purely decorative images - tells assistive tech to skip.
- Image filename matters too: `/charcoal-wool-overcoat.webp` beats `/IMG_2847.webp`.

### Byte budget

There’s no universal rule, but useful targets:

- **Hero images**: &lt; 200 KB for WebP, &lt; 300 KB for JPEG fallback
- **Inline content images**: &lt; 100 KB
- **Thumbnails**: &lt; 20 KB
- **Total page image weight**: &lt; 1 MB on mobile

### WordPress

WP 5.5+ adds `loading="lazy"` automatically and generates WebP from uploads (6.0+). The Modern Image Formats plugin or ShortPixel handles AVIF. Verify the generated `srcset` covers your real breakpoint range - WP’s default sizes don’t always match the active theme.

### Next.js (App Router)

```
import Image from "next/image";

<Image
  src="/photo.jpg"
  alt="Knee-length wool overcoat in charcoal, front view"
  width={1600}
  height={900}
  sizes="(max-width: 768px) 100vw, 50vw"
  priority={isHero}  // skips lazy-load + adds fetchpriority=high
/>
```

`next/image` auto-emits WebP, generates the `srcset`, and handles dimensions.

### Shopify

Use the `image_url` filter with format conversion:

```
<img
  src="{{ image | image_url: width: 800, format: 'webp' }}"
  srcset="{{ image | image_url: width: 400, format: 'webp' }} 400w,
          {{ image | image_url: width: 800, format: 'webp' }} 800w,
          {{ image | image_url: width: 1600, format: 'webp' }} 1600w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="{{ image.alt | escape }}"
  width="{{ image.width }}"
  height="{{ image.height }}"
  loading="lazy"
/>
```

## Common pitfalls

- **PNG for photos.** PNG is lossless - great for logos, terrible for photos. JPEG or WebP for photographs; PNG only for graphics with text, sharp edges, or transparency.
- **`loading="lazy"` on the LCP image.** Single biggest accidental LCP regression.
- **`alt=""` on meaningful images.** Empty alt tells screen readers to skip; it should only be used for decoration. A product photo with empty alt is broken.
- **Same-resolution image for every breakpoint.** A 3200px image served to a 320px mobile screen is 99% wasted bytes.
- **Repeating the caption in the alt.** Screen readers read both. Differentiate, or leave alt empty if the caption already covers it.

From diagnosis to deployment

## Find the issue. Ship the fix.

Use Learn to understand the problem, then run Serpwise against your own site to see what can be approved and deployed.

[Run free audit](/audit/) [Book a demo](/demo/)