The European Accessibility Act has been enforceable since June 28, 2025. If you build or maintain e-commerce stores for EU customers, your clients are legally required to meet WCAG 2.1 Level AA — and most of them have no idea how far behind they are.
This is not a future deadline. It is already in effect.
Here is what you actually need to implement, in order of impact.
What the EAA requires for e-commerce
The EAA applies to any business selling products or services to customers in the EU, regardless of where the business is registered. For e-commerce, the technical standard it points to is WCAG 2.1 Level AA.
The most common failure across EU stores — by a significant margin — is image alt text. Not missing aria-label on buttons. Not contrast ratios. Alt text. Specifically: product images, category banners, and promotional graphics with either empty alt="" (valid for decorative images, but often misused), missing alt attributes entirely, or values like "image1.jpg" or "DSC_0042".
A store with 500 products and 4 images per product has 2,000 images that each need a WCAG 2.1 AA-compliant description. Most stores have never audited this.
The WCAG 2.1 AA requirements for alt text (SC 1.1.1)
Success Criterion 1.1.1 Non-text Content requires that every non-decorative image has a text alternative that serves the equivalent purpose.
For e-commerce, this translates to:
<!-- ✗ Wrong — filename as alt text -->
<img src="nike-air-max-270-coral.jpg" alt="nike-air-max-270-coral.jpg">
<!-- ✗ Wrong — generic placeholder -->
<img src="nike-air-max-270-coral.jpg" alt="product image">
<!-- ✗ Wrong — starts with "image of" (redundant, screen readers announce the element type) -->
<img src="nike-air-max-270-coral.jpg" alt="image of a shoe">
<!-- ✓ Correct -->
<img src="nike-air-max-270-coral.jpg" alt="Nike Air Max 270 Women's running shoe in coral pink, side view">
<!-- ✓ Correct for decorative images -->
<img src="divider-pattern.svg" alt="">
The standard does not specify a character limit, but screen readers truncate after approximately 125 characters. Keep descriptions under that threshold and front-load the key information.
What the EAA also requires: the Annex V statement
This is the part most developers miss.
Beyond fixing technical issues, the EAA requires you to publish an Annex V accessibility statement on the website. This is a formal document that declares:
- Which WCAG 2.1 AA criteria the site meets
- Which criteria it does not meet, and why
- A contact mechanism for users to report accessibility issues
- A remediation timeline for known gaps
Publishing a statement saying "we comply with WCAG 2.1 AA" when you do not is explicitly prohibited. The statement must accurately reflect actual conformance.
How to audit alt text at scale
Option 1: Browser DevTools (for single pages)
Open DevTools → Console → run:
// Find all images missing alt attribute entirely
document.querySelectorAll('img:not([alt])').forEach(img => {
console.warn('Missing alt:', img.src);
});
// Find images with empty or placeholder alt text
document.querySelectorAll('img[alt]').forEach(img => {
const alt = img.alt.trim();
if (alt === '' && !img.getAttribute('role')) return; // decorative, OK
if (alt.match(/\.(jpg|jpeg|png|webp|gif|svg)/i)) {
console.warn('Filename as alt text:', img.src, '→', alt);
}
if (alt.length < 5 && alt !== '') {
console.warn('Suspiciously short alt text:', img.src, '→', alt);
}
});
Option 2: axe-core (for automated testing pipelines)
import { axe } from 'axe-core';
// Run in your test suite or CI pipeline
const results = await axe.run();
const altTextViolations = results.violations.filter(v =>
v.id === 'image-alt' || v.id === 'image-redundant-alt'
);
console.log(`Alt text violations: ${altTextViolations.length}`);
altTextViolations.forEach(v => {
v.nodes.forEach(node => {
console.log(node.html);
});
});
Option 3: Playwright + axe for full-site crawls
import { chromium } from 'playwright';
import AxeBuilder from '@axe-core/playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
const urls = [
'https://your-store.com/',
'https://your-store.com/products',
// add category and product pages
];
for (const url of urls) {
await page.goto(url);
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.analyze();
const imageIssues = results.violations.filter(v =>
v.tags.includes('cat.text-alternatives')
);
if (imageIssues.length > 0) {
console.log(`\n${url}: ${imageIssues.length} image accessibility issue(s)`);
imageIssues.forEach(issue => {
console.log(` ${issue.id}: ${issue.description}`);
issue.nodes.forEach(node => console.log(` → ${node.html}`));
});
}
}
await browser.close();
One important caveat: automated tools catch approximately 30–40% of WCAG issues. They are reliable for structural problems like missing alt attributes, but cannot judge whether a description is meaningful. "A shoe" technically passes automated checks. "Nike Air Max 270 Women's running shoe in coral pink" is what the standard actually requires.
Fixing alt text on Shopify
Shopify stores the alt attribute per image, not per product. When a merchant uploads an image without adding alt text, it defaults to empty.
Via Liquid template (check current state):
{% for image in product.images %}
<img
src="{{ image | img_url: '800x' }}"
alt="{{ image.alt | escape | default: product.title }}"
width="{{ image.width }}"
height="{{ image.height }}"
loading="lazy"
>
{% endfor %}
The default: product.title fallback is better than an empty alt, but it is not WCAG-compliant — the product title is not a description of the image. It is a temporary fix, not a solution.
For bulk alt text at scale, the Shopify Admin API exposes the alt field on ProductImage:
// Update alt text via Admin API
const response = await fetch(
`https://${shop}/admin/api/2024-01/products/${productId}/images/${imageId}.json`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': accessToken,
},
body: JSON.stringify({
image: {
id: imageId,
alt: 'Nike Air Max 270 Women\'s running shoe in coral pink, side view'
}
})
}
);
For stores with thousands of products, writing this at scale requires either generating descriptions programmatically (using a vision model) or integrating a tool that does it automatically. Altvisor — which we built specifically for this EU compliance gap — connects to Shopify and generates WCAG 2.1 AA-compliant alt text automatically on every image upload. It also generates the Annex V PDF.
Fixing alt text on WooCommerce
WordPress stores the alt text in wp_postmeta under the key _wp_attachment_image_alt. You can audit and update it programmatically:
// Find all images missing alt text
$args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => -1,
'post_status' => 'inherit',
);
$images = get_posts($args);
foreach ($images as $image) {
$alt = get_post_meta($image->ID, '_wp_attachment_image_alt', true);
if (empty(trim($alt))) {
// Log or process
error_log("Missing alt text: ID {$image->ID} — {$image->post_title}");
}
}
// Update alt text for a specific attachment
update_post_meta($attachment_id, '_wp_attachment_image_alt', 'Your descriptive alt text here');
For WooCommerce product images specifically, the woocommerce_product_get_image filter lets you intercept and modify alt text output without touching the database:
add_filter('woocommerce_product_get_image', function($html, $product) {
// Only modify if alt is missing or a filename
if (preg_match('/\.(jpg|jpeg|png|webp)/i', strip_tags($html))) {
$html = str_replace('alt="', 'alt="' . esc_attr($product->get_name()) . ' — ', $html);
}
return $html;
}, 10, 2);
Again, product name is a fallback. Real compliance needs descriptive alt text per image.
The developer's EAA compliance checklist
Before signing off on any EU e-commerce project:
- [ ] Every non-decorative
<img>has a descriptivealtattribute - [ ] Decorative images have
alt=""(empty string, not missing) - [ ] Alt text avoids "image of", "photo of", or filenames
- [ ] Alt text is under 125 characters (front-load key details)
- [ ] Product variant images describe the specific variant (colour, material, angle)
- [ ]
langattribute on<html>matches the page language - [ ] Heading hierarchy is logical (no skipping H1 → H3)
- [ ] All form inputs have associated
<label>elements - [ ] Colour contrast ratio is at least 4.5:1 for body text, 3:1 for large text
- [ ] All interactive elements are keyboard-accessible
- [ ] Focus indicators are visible and meet 3:1 contrast ratio
- [ ] Annex V accessibility statement is published on the site
- [ ] Statement accurately reflects actual conformance level
What the compliance landscape looks like right now
The EAA is enforced at the national level — each EU member state has a designated supervisory authority. Enforcement started in June 2025 and is currently focused on larger retailers, but SMB investigations are expected to increase through 2026.
The practical risk for most developers is not regulatory fines directly — it is client liability. Stores that receive accessibility complaints can face both regulatory investigation and civil claims. As the developer who built or maintains the store, your documentation of what you audited and fixed becomes relevant.
Running an axe-core audit and keeping the results is a reasonable starting point. Publishing an accurate Annex V statement is the legal requirement. The gap between those two steps is where most EU stores currently sit.
Building something for the EU market and want to share how you handle accessibility at scale? Drop a comment — particularly interested in how agencies are handling the Annex V statement requirement across multiple clients.
Tags: accessibility wcag shopify wordpress ecommerce webdev javascript php
Top comments (0)