How to Write Alt Text: 15 Examples for SEO and Accessibility

How to write alt text for screen readers and image search: 15 before/after examples, when to leave alt empty, and data from 14,321 images on 219 sites.

BugViso

14 min read

To write good alt text, describe what the image communicates in this context, in one short sentence, usually under 125 characters. Skip "image of" and file names. Use an empty alt="" for purely decorative images, and when an image is a link, describe where the link goes, not what the picture shows.

That definition sounds simple. The web still gets it wrong at scale. On 3 October 2026 we classified 14,321 images on 219 randomly sampled homepages. 28.3% of the homepages had at least one image with no alt attribute at all. 32.0% had a linked image or icon button that a screen reader announces with no name.

This guide gives you a decision process, 15 before/after examples across the image types you actually publish, the SEO side of alt text, and a script that audits alt quality, not just whether the attribute is present.


What Alt Text Is For

The alt attribute is the text alternative for an <img>. Screen readers announce it in place of the image. Browsers show it when the image fails to load. Search engines use it, together with the surrounding text, to understand what the image depicts.

WCAG 2.2 Success Criterion 1.1.1 Non-text Content (Level A) requires a text alternative that serves the equivalent purpose. The key word is purpose. The same photo of a red running shoe needs different alt text on a product page, in a blog post about marathon training, and as a link to the "Shoes" category.

The HTML standard's guidance on alternative text and the W3C's alt decision tree both come down to one question: if the image disappeared, what text would replace it so no one loses information?


What We Found on 14,321 Images

We drew 420 domains at random from Tranco list 94GG2 (ranks 1,001–50,000) and loaded each homepage in Chromium. We kept the 219 that served a real page and classified every <img> in the rendered DOM, after JavaScript and lazy-loading had run.

ClassificationImagesShare
Descriptive alt text present7,82254.6%
alt="" (marked decorative)2,78719.5%
Hidden from assistive tech (aria-hidden, role="presentation")2,26515.8%
No alt attribute at all8766.1%
Alt is a file name (IMG_2041.jpg, hero-v2-final)3652.5%
Alt longer than 150 characters990.7%
Placeholder word ("image", "logo", "photo", "icon")780.5%
Starts with "image of" / "picture of" / "photo of"290.2%

At the site level:

Metric (219 homepages)Result
Median images per homepage31
Homepages with ≥1 image missing alt62 (28.3%)
Homepages with an image-only link/button and no accessible name70 (32.0%)
Homepages failing axe-core's image-alt rule54 (24.7%), 617 elements
Homepages with any alt-text problem from the list above139 (63.5%)

Two observations. First, missing alt is now a minority problem: most CMSs and frameworks nudge authors to fill it in. The bigger failures are linked images with no name: logos, social icons and card thumbnails that are the only content of an <a>. A screen reader announces those as "link" and nothing else.

Second, almost a fifth of images use alt="". That is correct for decoration, and we can't tell from markup alone whether each one really is decorative. That judgement needs a human, which is exactly why automated checkers pass them silently.


The 5-Question Alt Text Decision Process

Work through these in order for every image:

  1. Is it purely decorative? Borders, background flourishes, a stock photo that repeats the headline. → alt="" (and never leave the attribute out).
  2. Is it a link or a button? → Alt describes the destination or action: "BugViso home", "Download the report (PDF)".
  3. Does it contain text? → Alt includes the text, unless that text also appears right next to the image.
  4. Is it complex (a chart, diagram or map)? → Short alt giving the conclusion, plus the full data in a caption, table or link.
  5. Otherwise → One sentence describing what matters in this context.

15 Before/After Alt Text Examples

Product and e-commerce images

1. Product photo on a product page

html
<!-- ❌ Says nothing a shopper needs -->
<img src="shoe-red.jpg" alt="shoe">

<!-- ✅ The details that distinguish this variant -->
<img src="shoe-red.jpg" alt="Trail running shoe in red with a black Vibram sole, side view">

2. Gallery of the same product. Each angle needs its own alt. Five images with identical alt text make a screen reader user hear the same sentence five times.

html
<img src="p1.jpg" alt="Front view: lace-up closure and padded tongue">
<img src="p2.jpg" alt="Sole: lug pattern for loose terrain">
<img src="p3.jpg" alt="Shoe worn on foot, showing heel fit">

3. Product thumbnail that links to the product page

html
<!-- ❌ Describes the picture; the link has no destination -->
<a href="/shoes/trail-x"><img src="thumb.jpg" alt="red shoe"></a>

<!-- ✅ Names the destination; the product name is the link's purpose -->
<a href="/shoes/trail-x"><img src="thumb.jpg" alt="Trail X running shoe"></a>

Logos, icons and buttons

4. Header logo that links home

html
<!-- ❌ 'logo' is a placeholder, and the link has no destination -->
<a href="/"><img src="logo.svg" alt="logo"></a>

<!-- ✅ -->
<a href="/"><img src="logo.svg" alt="BugViso home"></a>

5. Social media icon links. This is the most common "no accessible name" failure in our data.

html
<!-- ❌ Announced as "link, link, link" -->
<a href="https://www.linkedin.com/company/example"><img src="li.svg" alt=""></a>

<!-- ✅ -->
<a href="https://www.linkedin.com/company/example"><img src="li.svg" alt="Example on LinkedIn"></a>

6. Icon next to visible text

html
<!-- ✅ The text already names the action, so the icon is decorative -->
<button><img src="download.svg" alt=""> Download report</button>

7. Icon-only button. No visible text, so the image must carry the name.

html
<button><img src="search.svg" alt="Search"></button>

Content and editorial images

8. Team or author photo

html
<!-- ❌ -->
<img src="dsc_0042.jpg" alt="DSC_0042">
<!-- ✅ In a bio, name and role are what matter -->
<img src="maria.jpg" alt="Maria Chen, Head of Engineering">

9. Blog post illustration that supports the point

html
<!-- ❌ Generic -->
<img src="cls.png" alt="screenshot">
<!-- ✅ What the reader should notice -->
<img src="cls.png" alt="Article text jumping down 180px when an ad loads above it">

10. Stock photo that adds nothing

html
<!-- ✅ A smiling person at a laptop next to the heading 'Grow your business' is decoration -->
<img src="stock-laptop.jpg" alt="">

11. Image containing text (a promo banner)

html
<!-- ✅ The banner's words ARE the content -->
<img src="sale.png" alt="Autumn sale: 30% off all plans until 31 October">

Complex images

12. Chart. Give the conclusion in alt, and the data in the page.

html
<figure>
  <img src="chart.png" alt="Bar chart: missing alt attributes fell from 9% to 6% of images">
  <figcaption>Full data in the table below.</figcaption>
</figure>

13. Screenshot in documentation

html
<img src="settings.png" alt="Settings page with the 'Enable scheduled scans' toggle switched on">

14. Map image. Describe what the map is for, not every street.

html
<img src="map.png" alt="Map showing our office two blocks north of Central Station">

15. Before/after comparison

html
<img src="before.png" alt="Before: grey 2.5:1 body text on white">
<img src="after.png" alt="After: dark grey 4.5:1 body text on white">

Mistakes That Make Alt Text Worse Than None

PatternWhy it failsFix
Missing alt attributeScreen readers may read the file name or full URL aloudAlways include alt, empty if decorative
"Image of…" / "Picture of…"The screen reader already announces "image"Start with the subject
File names (IMG_2041)Meaningless to everyoneDescribe the content
Keyword stuffingReads as spam to users and to GoogleWrite for the user; keywords only if they fit naturally
Same alt as the adjacent captionUsers hear it twicealt="" or a shorter, different description
300-character essaysCan't be paused or navigatedShort alt + caption or linked long description

Another frequent problem is decorative images that aren't marked decorative. A carousel of eight stock photos with alt text like "business meeting" adds eight useless stops for a keyboard or screen reader user.


Alt Text and SEO: What Actually Matters

Google uses alt text as one of several signals for image understanding. Its image SEO best practices recommend descriptive, useful alt text and warn against keyword stuffing. In practice:

  • Descriptive beats keyword-loaded. "Red trail running shoe with Vibram sole" helps image search more than "running shoes best running shoes cheap".
  • File names matter too. trail-x-red-side.jpg reinforces the alt. IMG_2041.jpg and hero-v2-final.png reinforce nothing. In our sample, 2.5% of images even used the file name as the alt.
  • Context counts. Captions, nearby headings and structured data (Product → image) all help search engines understand the image.
  • Linked images pass anchor text. For an image link, the alt text works as the link's anchor text, which is one more reason never to leave it empty.

Good alt text and good image SEO are the same practice. Heavy, unoptimised images, on the other hand, are a separate problem, covered in our guide to image optimization with WebP and AVIF.


Audit Alt Text Quality With a Script

Presence checkers only tell you whether alt exists. This script also flags file-name alts, placeholder words, "image of" prefixes, overlong alts and image-only links with no name.

python
#!/usr/bin/env python3
"""Alt text auditor: finds images whose alt text fails users (not just missing ones).

Usage:  pip install httpx beautifulsoup4
        python3 alt_text_audit.py https://example.com https://example.com/pricing
        python3 alt_text_audit.py --sitemap https://example.com/sitemap.xml --limit 100
"""
import argparse, asyncio, re, sys
from collections import Counter
from urllib.parse import urljoin, urlsplit

import httpx
from bs4 import BeautifulSoup

GENERIC = {"image", "img", "photo", "picture", "pic", "logo", "icon", "banner", "graphic",
           "thumbnail", "placeholder", "spacer", "alt", "null", "undefined", "untitled"}
FILEISH = re.compile(r"\.(jpe?g|png|webp|gif|svg|avif)$|^(img|image|dsc|dscn|pxl|photo|screenshot)[-_ ]?\d+|"
                     r"[-_](final|v\d+|copy|edit|crop)\b|^[0-9a-f]{12,}$", re.I)


def classify(img):
    if img.find_parent(attrs={"aria-hidden": "true"}) or img.get("role") in ("presentation", "none"):
        return None
    alt = img.get("alt")
    parent = img.find_parent(["a", "button"])
    if parent is not None and not parent.get_text(strip=True) and not parent.get("aria-label") and not (alt or "").strip():
        return "LINK-NO-NAME"
    if alt is None:
        src = (img.get("src") or "").lower()
        if src.startswith("data:") or re.search(r"placeholder|grey|gray|blank|spacer|lazy", src):
            return "PLACEHOLDER"   # lazy-load stand-in: re-check the rendered DOM
        return "MISSING"
    a = alt.strip()
    if not a:
        return "DECORATIVE"
    src = urlsplit(img.get("src") or "").path.rsplit("/", 1)[-1].rsplit(".", 1)[0].lower()
    if FILEISH.search(a) or (src and a.lower() == src):
        return "FILENAME"
    if a.lower() in GENERIC:
        return "GENERIC"
    if re.match(r"(an? )?(image|picture|photo|graphic) of\b", a, re.I):
        return "REDUNDANT"
    if len(a) > 150:
        return "TOO-LONG"
    return "OK"


async def main(urls, sitemap, limit):
    async with httpx.AsyncClient(timeout=20, follow_redirects=True,
                                 headers={"User-Agent": "Mozilla/5.0 (compatible; alt-audit/1.0)"}) as client:
        if sitemap:
            xml = (await client.get(sitemap)).text
            urls += re.findall(r"<loc>\s*([^<\s]+)\s*</loc>", xml)
        urls = [u for u in dict.fromkeys(urls) if not u.endswith(".xml")][:limit]
        totals = Counter()
        for url in urls:
            try:
                r = await client.get(url)
            except httpx.HTTPError as e:
                print(f"! {url}: {e}", file=sys.stderr); continue
            soup = BeautifulSoup(r.text, "html.parser")
            found = [(classify(i), i) for i in soup.find_all("img")]
            found = [(c, i) for c, i in found if c]
            totals.update(c for c, _ in found)
            bad = [(c, i) for c, i in found if c not in ("OK", "DECORATIVE", "PLACEHOLDER")]
            print(f"\n{url}  ({len(found)} images, {len(bad)} problems)")
            for c, i in bad[:15]:
                src = urljoin(url, i.get("src") or i.get("data-src") or "")
                print(f"  {c:12} alt={i.get('alt')!r:.50}  {src[:90]}")
    print("\nSUMMARY  " + "  ".join(f"{k}={v}" for k, v in totals.most_common()))


if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("urls", nargs="*")
    ap.add_argument("--sitemap")
    ap.add_argument("--limit", type=int, default=50)
    a = ap.parse_args()
    asyncio.run(main(a.urls, a.sitemap, a.limit))

On a large news homepage, it found 66 lazy-load placeholders with no alt in the static HTML. The real images replace them after JavaScript runs, so those aren't true failures, and the script reports them as PLACEHOLDER rather than MISSING. It also found two alts starting with "A photo of…", five alts over 150 characters, and five image-only links with no name. Re-check any PLACEHOLDER or doubtful result in a rendered browser before filing it as a bug.


How BugViso Audits Images Automatically

BugViso checks images in two places on every audited page. The WCAG accessibility audit runs axe-core's image-alt and related rules (such as link-name and button-name) in a real Chromium render. That catches missing alternatives and image-only links with no accessible name after lazy-loading has finished.

The Advanced Image SEO & CLS check in the SEO intelligence engine looks at quality signals a plain accessibility rule ignores. It flags images with missing alt attributes and non-descriptive file names (hashes, image_32.png, hero-v2-final.png). It also flags images without explicit width and height, which cause layout shift. On a multi-page crawl, these findings roll up across the site, so a logo or icon set with no alt text shows up as one shared template problem.

Each issue comes with a fix in the remediation playbook and in the PDF report. You can run a free BugViso scan to see the image findings for any page.


Alt Text Checklist

  • Every <img> has an alt attribute, even if it's empty.
  • Decorative images use alt="", not a missing attribute and not alt="image".
  • Image-only links and buttons describe the destination or action.
  • No alt starts with "image of", "picture of" or "photo of".
  • No file names, hashes or placeholder words as alt text.
  • Text inside images appears in the alt (or right next to the image).
  • Charts give their conclusion in alt and their data in the page.
  • Product galleries use a different alt for each angle.
  • Alt text is under ~125 characters; longer descriptions go in a caption.
  • Image file names are descriptive and hyphenated.

FAQ

How long should alt text be?

Usually one sentence, under about 125 characters. There's no hard limit in WCAG, but long alts can't be paused or skimmed by screen reader users. If an image needs more, put a short alt on it and the detail in a caption or the surrounding text.

Should every image have alt text?

Every image needs an alt attribute, but not every image needs alt text. Decorative images get alt="", which tells screen readers to skip them. Leaving the attribute out is a failure, because some screen readers then read the file name aloud.

Does alt text help SEO?

Yes. It's one of the signals Google uses to understand images, and for linked images it works as anchor text. Descriptive alt text helps; keyword-stuffed alt text doesn't, and Google's guidance specifically warns against it.

What is the difference between alt text and a caption?

Alt text replaces the image for people who can't see it, and it's invisible to sighted users. A caption is visible to everyone and adds context. If a caption already describes the image fully, the alt can be empty or shorter, so screen reader users don't hear the same text twice.

Can AI write my alt text?

AI can draft a description of what's in an image. It can't know what the image is for on your page, and that's what alt text must convey. Use AI drafts as a starting point, and have someone who knows the page's purpose edit them.


Conclusion

Alt text is short to write and easy to get subtly wrong. Describe what the image does on this page, name the destination for linked images, and use alt="" for decoration. A BugViso audit flags missing alts, file-name alts and nameless image links across every page it crawls.

For the other failures that usually show up alongside missing alt text, see our guide to the most common WCAG violations and how to fix them, and our walkthrough on fixing color contrast errors.

Found this useful? Share it.

See where your site stands

Run a free BugViso audit for SEO, speed, accessibility and AI search readiness — with fixes you can ship today.