Image SEO: A Technical Guide to Alt Text, Formats and Loading
Image SEO comes down to six things Google reads from your HTML: descriptive alt text, real filenames, next-gen formats, correct lazy-loading, dimensions, and image sitemaps.
Image SEO reduces to six things Google reads straight from your HTML and headers: descriptive alt text, a real filename, a modern format, the right loading behaviour, declared dimensions, and inclusion in a sitemap. None of these require JavaScript to detect, and five of the six are attributes on the <img> tag itself. Get them right and your images become eligible for image search, contribute to rich results, and stop dragging down Core Web Vitals.
Alt text: describe, do not stuff
Google uses the alt attribute to understand what an image depicts, for both web search and Google Images. The guidance is specific: write descriptive, context-relevant text, not a keyword list.
<img src="dalmatian-puppy-fetch.jpg" alt="Dalmatian puppy playing fetch in a park">
<!-- not: alt="puppy dog baby dog pup pups fetch park dog" -->
There are two distinct failure modes, and they are not the same:
- Missing alt entirely. Google has no text description of the image, and a screen reader announces the filename or nothing. Crawlinx flags this as
images.missing_alt. - Decorative image with alt text. A spacer, divider, or purely ornamental graphic should carry an explicit empty
alt="", which tells assistive technology to skip it. Omittingaltand declaringalt=""mean different things — the first is an oversight, the second is a deliberate "this image carries no information."
Do not pad alt text to game rankings. Overlong, stuffed alt text is a weaker signal than a short, accurate one, and Crawlinx flags descriptions that run past a sensible length as images.alt_too_long. A screen reader and Googlebot both read the alt attribute, so writing for one serves the other.
Filenames are still a ranking signal
Google uses the image filename as one of the signals for image search. This is unusual — most on-page micro-signals have faded — but Google's own documentation still cites puppy.jpg as better than IMG00023.jpg. The filename is readable from the src attribute without ever fetching the image, so it costs nothing to get right at export time.
Use short, hyphen-separated, descriptive names: black-kitten-sleeping.jpg, not DSC_0428.JPG or image1.png. Reference the same image with the same URL consistently across the site, and place each image near the text it relates to so Google can associate the two.
Next-gen formats with fallbacks
WebP and AVIF are Google's recommended formats for performance; JPEG and PNG are legacy. AVIF generally compresses smaller than WebP, and WebP smaller than JPEG at equivalent quality, which directly helps Largest Contentful Paint on image-heavy pages.
Serve modern formats with a fallback so older clients still get a working image. The <picture> element does this cleanly:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="City skyline at dusk" width="1600" height="900">
</picture>
The browser picks the first format it supports; the <img> inside is the universal fallback and is where your alt, width, and height belong. Note that Google does not index CSS background-image — anything you want in image search must be a real <img> (or <picture>) in the markup.
Lazy-loading: never on the LCP image
loading="lazy" defers off-screen images until the user scrolls near them, which is correct for images below the fold. Google supports the attribute and recommends it — with one hard exception it states explicitly: do not lazy-load an image that is a candidate for Largest Contentful Paint.
The hero image, or any large above-the-fold image, is frequently the LCP element. Marking it loading="lazy" forces the browser to wait before fetching the single most important pixel on the page, which pushes LCP past the 2.5-second "good" threshold. This is one of the most common Core Web Vitals mistakes on modern sites.
The correct treatment for the LCP image is the opposite of lazy: load it eagerly and hint its priority.
<!-- Below the fold: lazy is right -->
<img src="gallery-12.webp" alt="…" loading="lazy" width="800" height="600">
<!-- The hero / LCP image: never lazy -->
<img src="hero.webp" alt="…" fetchpriority="high" width="1600" height="900">
fetchpriority="high" tells the browser to fetch the hero ahead of lower-priority resources. In frameworks this is often abstracted — Next.js next/image lazy-loads by default and exposes a priority prop that sets eager loading plus fetchpriority="high" for exactly this case. The rule to remember: lazy-load everything below the fold, load the LCP image eagerly with high priority. The performance mechanics are in our Core Web Vitals guide.
Dimensions prevent layout shift
An <img> without width and height gives the browser no idea how much space to reserve, so surrounding content jumps when the image finally loads. That jump is Cumulative Layout Shift, the third Core Web Vital. Declaring the intrinsic width and height (or a CSS aspect-ratio) lets the browser hold the space before the bytes arrive.
<img src="chart.webp" alt="Revenue by quarter" width="1200" height="675">
This is independent of, and complementary to, the lazy-loading rule — one prevents layout shift, the other governs load timing. Crawlinx flags images without declared dimensions as images.missing_dimensions, and images that return a non-200 or fail to load as images.broken.
Structured data and og:image
Images referenced in structured data have a higher chance of appearing in rich results. Article, Recipe, and Product markup all expect an image property, and Google requires those image URLs to be crawlable and indexable — never block them in robots.txt or serve them behind login. Signal the page's primary image with schema and with an Open Graph og:image for the social and link-preview surface. Getting the markup right is covered in our structured data guide.
Image sitemaps: only two tags survive
Google still recommends listing important images in a sitemap, either as a dedicated image sitemap or via the <image:image> extension on your existing URL entries. But the image sitemap namespace was cut down: image:caption, image:title, image:license, and image:geo_location are all deprecated. Only two tags remain in use:
<url>
<loc>https://example.com/products/tent</loc>
<image:image>
<image:loc>https://example.com/img/tent-4-person.webp</image:loc>
</image:image>
</url>
Do not spend effort populating the removed fields — Google ignores them. Declare the xmlns:image namespace, list <image:image> with an <image:loc> per image (up to 1,000 images per page URL), and put your descriptive metadata where Google actually reads it: the alt text and the surrounding page content. How sitemaps are declared and submitted is covered in the XML sitemaps guide.
How Crawlinx detects image problems
Crawlinx parses every <img> during the crawl and checks it against these rules without fetching image bytes where the signal is in the HTML: missing alt text (images.missing_alt), overlong stuffed alt (images.alt_too_long), absent dimensions that risk layout shift (images.missing_dimensions), and images that fail to load (images.broken). Run these alongside the technical SEO audit checklist so image issues surface next to the crawl, index, and performance checks they interact with.
Takeaway
Image SEO is mostly attribute hygiene on the <img> tag. Write descriptive alt text and mark decorative images with alt=""; keep real, hyphenated filenames; serve WebP or AVIF with a <picture> fallback; declare width and height to stop layout shift; never lazy-load the LCP image and give it fetchpriority="high" instead; and list images in a sitemap using the only two tags Google still reads, image:image and image:loc.
Audit your own site — free
77 checks, internal PageRank, render-diff. No signup, results in ~30s.