Fix
The download link that never says it is a 40 MB PDF
File type and size are part of what a link is. "Download brochure" reads like one more page — until it hands the browser to a PDF viewer, or starts forty megabytes down a phone connection nobody agreed to.
Who this locks out
A bare "Download brochure" link springs a 40 MB PDF on people who could not see it coming.
- Screen-reader users tipped without warning out of the browser into a PDF viewer with different commands
- Shoppers on slow or metered connections, committed to a download they were never allowed to size first
- Anyone deciding whether a link is worth following, denied the one fact that would settle it
The transform
Before
<a href="/downloads/size-guide.pdf">Download the size guide</a> After
<a href="/downloads/size-guide.pdf">Download the size guide (PDF, 2 MB)</a> Detection
How this is tested here
Every scan runs three independent engines and 19 custom checks against your rendered pages, and records which engine flagged what. These are the real rules behind this fix family.
| Criterion | Level | Detected by | What we do |
|---|---|---|---|
| 2.4.4 Link Purpose (In Context) Most affects: People who are blind · People with cognitive disabilities · People with motor impairments | A | axe-core (area-alt, link-name) · IBM Equal Access (a_text_purpose) · Klarvo probe (klarvo.ambiguous-link) | auto |
What Klarvo Access does
Klarvo finds document links that hide their format, verifies the real type and size of each file through a hardened client at fix-generation time, and appends the annotation server-side — measured metadata only, with anything unverifiable routed to a person.
Auto-applied
Generated, then applied server-side in the HTML your store actually serves — and independently re-validated in the served page before it counts as resolved.
An automated finding is evidence, not a certificate. Conformance is certified only by the professional audit — how that works.
Do it yourself
Fixing this by hand
What a bare document link costs your store
Somewhere on your store there is a link that says “Download the size guide”, and nothing else. The shopper who follows it finds out what it really was only after clicking: the browser hands over to a PDF viewer, or a 38 MB file starts down a phone connection, or a spreadsheet lands on a tablet with nothing installed to open it. Every one of those outcomes was knowable in advance. The link just never said.
The cost lands unevenly. A screen-reader user who follows an unannounced PDF link is tipped out of the browsing interface they know into a document viewer with different commands and different behaviour — and if the PDF itself is poorly tagged, into a document that reads as very little at all. Warned, they can choose the moment, or choose not to. Unwarned, the switch simply happens to them, mid-task. A shopper on a metered or rural connection commits to a download they were never allowed to size; forty megabytes is real money or real minutes when it arrives unannounced. And every shopper deciding where to click is denied the one fact that would have made the decision easy — which makes this a conversion problem wearing an accessibility hat.
WooCommerce stores accumulate these links faster than most sites: size guides and care instructions on product pages, spec sheets and CAD drawings in B2B catalogues, warranty terms, delivery and returns policies exported to PDF, wholesale price lists, instruction manuals. Each is a small promise to the shopper about what happens next, and a bare “Download” keeps none of it.
The standard’s position, stated honestly. WCAG 2.4.4 Link Purpose (In Context), Level A, asks that the purpose of every link be determinable from its text together with its context, so that people can decide whether to follow it; the stricter AAA criterion, 2.4.9, asks the link text alone to carry it. Neither criterion mandates file type or size in so many words, and this page will not pretend otherwise. Naming the format and weight of a document is a technique-level enhancement in service of the criterion’s intent — it is what “deciding whether to follow” means when the destination is not a page — and MDN’s guidance for the anchor element recommends exactly this whenever a link leads to a non-HTML resource. Klarvo files it that way: an advisory serving 2.4.4, not a failure of it.
How it is detected here
No engine in the scan carries a named rule for this. axe-core’s link-name fires when a link has no accessible name at all — that is the empty-links family — and a link reading “Download brochure” passes every automated engine, because engines check that a name exists, not that it says enough. The same honest gap sits behind the ambiguous-link-text family: informativeness is not something a generic rule can score.
So the finding comes from Klarvo’s own deterministic pass over the served page. It collects links whose destination is a document — PDF and the Office formats: .pdf, .doc and .docx, .xls and .xlsx, .ppt and .pptx — and flags the ones whose visible text carries neither a file type nor a size. A link that already announces itself is left alone. And because no criterion mandates the metadata, the finding is filed as an advisory in service of 2.4.4; the report keeps that distinction rather than inflating it.
What Klarvo does about it
This family is auto tier, behind a verification gate, and the gate is the point: the annotation is measured, never guessed.
The work happens at fix-generation time — while the fix is being built, never while a shopper waits on a page. The engine asks the document itself, by requesting the file’s headers through a deliberately narrow client. That client is hardened against being turned into a probe — it refuses private and internal addresses, the SSRF class of problem — it checks every redirect before following it, and it is bounded in time and size: it reads the headers that state the content type and length rather than pulling forty megabytes down to weigh them.
Then it applies a standard of evidence. Only when both facts — the type and the size — are independently verified as trustworthy is the fix applied: the annotation is appended to the link text server-side, in the HTML your store serves, in the form at the top of this page — ” (PDF, 2 MB)”. If metadata is present but cannot be verified — the declared type and the file disagree, say, or a redirect crosses somewhere the client will not vouch for — the finding routes to your review queue carrying what was found, for a person to settle. If the metadata is simply unavailable — the host answers with nothing usable — it routes to report, and nothing is applied. A guessed size would be worse than none: the first shopper who waits out a “2 MB” download that runs to forty learns to distrust every annotation on your shop, and that trust is the whole value of the label.
The operation is idempotent — a link already carrying an annotation is never given a second — and the result is then checked rather than assumed: the page is fetched again independently, the appended text has to be present in the served HTML, and the link before and after is kept as evidence. An automated finding is evidence, not a certificate, here as everywhere.
How to fix it yourself
The pattern is the whole fix: name, format, weight, in the visible link text.
<a href="/downloads/size-guide.pdf">Size guide (PDF, 2 MB)</a>
In the text — not in a title attribute, which touch users never see and keyboard users rarely meet, and not in an icon alone, which says nothing to a screen reader unless it is separately named. Visible text serves everyone at once, which is rather the point: the sighted shopper deciding whether to tap is reading the same warning the screen reader announces.
Find the true numbers in the Media Library. Click any file and the attachment details show its type and size. Round to something a human uses — “2 MB”, not “1,966,080 bytes”; WordPress’s own size_format() exists for exactly this.
Hand-written links — the common case — are edited where they were made: the paragraph in the product description, the policy page, the FAQ. It is honest, five-second work per link, and the Media Library has the numbers open in the next tab.
Generated document lists can carry the metadata programmatically. If a template renders links from attachments:
$path = get_attached_file( $attachment_id );
$type = strtoupper( pathinfo( $path, PATHINFO_EXTENSION ) );
$size = size_format( (int) filesize( $path ) );
printf(
'<a href="%s">%s (%s, %s)</a>',
esc_url( wp_get_attachment_url( $attachment_id ) ),
esc_html( get_the_title( $attachment_id ) ),
esc_html( $type ),
esc_html( $size )
);
WooCommerce downloadable products have a spot most stores miss: the Name you give each file under Product data → Downloadable files becomes the link text your customer meets in the order confirmation email and under My Account → Downloads. “invoice-template-v3-final” is a filename; “Invoice template (XLSX, 1 MB)” is a link. Edit the name field, not just the page copy.
Documents you do not host — a manufacturer’s manual on their domain — you can still describe: download it once, note the type and weight, and label the link. If the manufacturer replaces the file often, link to their download page instead and say so: “Manual — on the manufacturer’s site”.
Icon-only download buttons need a name before they need metadata. A nameless download icon is the empty-links family’s territory; once the control has an accessible name, the format and size belong inside it.
Then clear your caches, and make the label part of the upload habit: every document that enters the Media Library should leave a type and a weight in whatever link points at it. The scan will catch the ones you forget.
How you know it worked
Read the store the way a screen reader does. In VoiceOver or NVDA, pull up the links list on a page that carries documents: each document link should announce itself completely — “Size guide, PDF, 2 megabytes, link” — with no need to follow it to find out. That list is precisely the test the bare link was failing.
Then check the numbers are true, because a wrong annotation is worse than a missing one. The Media Library states each file’s size; compare anything hand-typed against it. If you have replaced a document since labelling its link, re-check the pair — the text does not update itself when the file changes, which is exactly the drift a re-scan is there to catch.
Walk the money pages separately: the product page with the size guide, the delivery and returns policies, and — for downloadable products — a test order’s confirmation email and the My Account downloads screen, which render the file name you set rather than the page copy.
Then re-scan. The advisory clears when the served HTML carries the annotation; where Klarvo applied it, the re-validation has already fetched the page fresh and confirmed the appended text is present, with the link before and after kept as the record. And spend one honest moment on the shopper’s side of it: open the labelled link on a phone. Knowing what is coming turns the click from a gamble into a choice — for every customer, not only the ones the standard names.
Sources: W3C WAI — Understanding SC 2.4.4: Link Purpose (In Context) · W3C WAI — Understanding SC 2.4.9: Link Purpose (Link Only) · W3C WAI — Technique H30: Providing link text that describes the purpose of a link for anchor elements · W3C WAI — Technique G91: Providing link text that describes the purpose of a link · Deque University — axe rule link-name (axe-core 4.12) · MDN — <a>: The Anchor element (linking to non-HTML resources)
FAQ
Questions this raises
Does WCAG actually require file type and size in link text?
No, and the report never claims it does. Criterion 2.4.4 asks that the purpose of a link be determinable so people can decide whether to follow it; announcing that the destination is a 2 MB PDF rather than a page is a technique-level way of serving that intent, and it is what MDN recommends whenever a link leads to a non-HTML resource. Klarvo files it as an advisory enhancement in service of 2.4.4 — best practice stated plainly, not inflated into a failure.
Where does the appended text come from — is it ever guessed?
Never. At fix-generation time the engine requests the document headers through a hardened, redirect-checked, bounded client, and the annotation is applied only when the type and the size are both independently verified. Metadata that cannot be verified goes to your review queue with what was found; metadata that is unavailable is reported, and nothing is applied. The text your shoppers read is a measurement, not an estimate.
What happens when I replace a PDF with a new version?
The annotation is ordinary text in the page, stating the file as it was verified when the fix was generated — nothing fetches anything while a shopper waits, so the text does not silently track the file. When a later scan finds the link and the document disagreeing, the finding resurfaces and the annotation is regenerated from freshly verified headers.
Find out whether your store has this one.
The free scan checks your real pages — home, product, populated basket, hydrated checkout — with all three engines and all 19 Klarvo checks, and tells you exactly what it found and where.