NNicheStackTutorials
← All tutorials
SEO & Web Vitals

Static Site Image Optimization SEO Checklist (WebP, Dimensions, Alt Text)

Cut image payload 78% on a 120-post Hugo blog. Checklist covers build-time conversion, srcset, and alt text patterns that rank.

·13 min read·SEO & Web Vitals
Static Site Image Optimization SEO Checklist (WebP, Dimensions, Alt Text) cover

Site: 120 tutorial posts, ~8 images each, Hugo static export. Before: 4.2GB deploy, image SEO warnings in Ahrefs, image search traffic near zero. After: 940MB deploy, 340% increase in Google Image clicks over 90 days.

Checklist overview

□ Convert to WebP/AVIF at build time
□ Explicit width + height on every <img>
□ srcset for responsive sizes
□ Descriptive alt (not keyword stuffing)
□ Filename: post-topic-step-2.webp
□ Lazy load below fold only
□ Image sitemap or indexable /images/ paths

Build-time conversion (Hugo Pipes)

{{- $img := resources.Get .Destination -}}
{{- $sizes := slice 400 800 1200 -}}
{{- $srcset := slice -}}
{{- range $sizes -}}
  {{- $resized := $img.Resize (printf "%dx webp q80" .) -}}
  {{- $srcset = $srcset | append (printf "%s %dw" $resized.RelPermalink .) -}}
{{- end -}}
<img src="{{ ($img.Resize "800x webp q80").RelPermalink }}"
     srcset="{{ delimit $srcset ", " }}"
     sizes="(max-width: 600px) 100vw, 800px"
     alt="{{ .Text }}" width="800" height="{{ div (mul 800 $img.Height) $img.Width }}"
     loading="lazy" decoding="async">

Render hook: layouts/_default/_markup/render-image.html

Astro equivalent

import { Image } from 'astro:assets';
<Image src={import('./screenshot.png')} alt="VS Code terminal showing build output"
       widths={[400, 800, 1200]} formats={['webp', 'avif']} loading="lazy" />

Alt text formula that ranks

Bad: alt="seo image optimization webp" Good: alt="Lighthouse performance panel showing LCP improved from 3.2s to 1.0s after WebP conversion"

Pattern: [What it shows] + [context from surrounding heading]

Filename matters

Rename before commit:

IMG_2847.png  →  hugo-webp-render-hook-output.webp
screenshot.png → astro-image-component-srcset-example.webp

Google Image uses filename + alt + page context.

OG / Twitter images (separate from content images)

1200×630 WebP, < 200KB. Don't reuse tiny thumbnails — social previews affect CTR which affects rankings indirectly.

Image sitemap

<url>
  <loc>https://example.com/posts/image-seo/</loc>
  <image:image>
    <image:loc>https://example.com/images/hugo-webp-render-hook-output.webp</image:loc>
    <image:title>Hugo WebP render hook output</image:title>
  </image:image>
</url>

Hugo: custom sitemap template. Astro: @astrojs/sitemap with image plugin.

Common errors

ErrorFix
resources.Get: resource not foundMove from static/ to assets/
Blurry on retinaAdd 2x size in srcset (1600w for 800px display)
LCP regressionFirst image: loading="eager" + preload
CLS from missing dimensionsAlways output width/height attributes

Audit script

# Find images missing alt in built HTML
grep -r '<img' public/ | grep -v 'alt=' | head

# Find oversized images
find public -name '*.png' -size +200k -exec ls -lh {} \;

Results

Total image weight: 4.2GB → 940MB (-78%)
LCP p75: 2.8s → 1.2s
Google Image clicks: 42/mo → 185/mo
Ahrefs image SEO issues: 890 → 12

Image SEO is boring work. It's also the highest ROI fix on tutorial blogs.

Tags: Image SEOWebPsrcsetAlt TextHugo