PDF Metadata and Accessibility: What the EAA Means for Your Documents
If you generate PDFs as part of a product sold in the EU — invoices, contracts, statements, tickets, reports — the European Accessibility Act (EAA) applies to you starting June 28, 2025. The directive (EU 2019/882) doesn't mention "PDF" by name, but it requires that digital documents distributed to consumers be perceivable, operable, and understandable. In practice, that means tagged, metadata-rich PDFs that conform to PDF/UA-1 (ISO 14289-1).
Most PDF pipelines I've audited fail this. They produce visually correct documents that are completely opaque to screen readers. Below is what actually changes at the code level.
What the EAA expects from a PDF
The act references the EN 301 549 standard, which in turn points to PDF/UA for documents. The non-negotiable requirements:
- A logical structure tree (tags) describing headings, paragraphs, lists, tables, and figures.
- A reading order that matches the visual order.
- Document metadata: title, language, and
DisplayDocTitleset so the title (not the filename) shows in viewers. - Alt text for every meaningful image; artifacts marked for decorative content.
- Unicode-mapped text — no glyph-only output that breaks copy-paste and TTS.
- Tagged tables with proper
<TH>scope and<TR>/<TD>structure. - Form fields with tooltips (
/TU) and a tab order.
If your generator emits a "flat" PDF (think: HTML rendered to canvas, then printed), you're shipping something that is technically a PDF but structurally an image. Screen readers will announce nothing useful.
The metadata baseline
Start here. These properties cost almost nothing to set and are checked by every accessibility validator:
/Title "Invoice INV-2025-0142"
/Lang "en-US"
/ViewerPreferences << /DisplayDocTitle true >>
/MarkInfo << /Marked true >>
/StructTreeRoot ...In XMP metadata, you also want:
xml<rdf:Description rdf:about="" xmlns:pdfuaid="http://www.aiim.org/pdfua/ns/id/"> <pdfuaid:part>1</pdfuaid:part> </rdf:Description>
Without pdfuaid:part = 1, validators will not treat the file as claiming PDF/UA conformance, even if everything else is correct.
What this looks like in HTML-to-PDF pipelines
If you generate PDFs from HTML (the most common backend approach), the renderer needs to map HTML semantics to PDF tags. Headless Chrome does not do this in a useful way — its tagged output is incomplete and rarely passes PAC 2024 (the de facto PDF/UA validator).
Tools that do produce tagged PDF/UA output from HTML rely on you writing accessible HTML in the first place:
html<!doctype html> <html lang="en-US"> <head><title>Invoice INV-2025-0142</title></head> <body> <h1>Invoice INV-2025-0142</h1> <table> <caption>Line items</caption> <thead> <tr><th scope="col">Description</th><th scope="col">Qty</th><th scope="col">Total</th></tr> </thead> <tbody> <tr><td>API credits</td><td>1,000</td><td>€49.00</td></tr> </tbody> </table> <img src="signature.png" alt="Signature of Jane Doe, CFO"> <img src="divider.svg" alt="" role="presentation"> </body> </html>
Three things to notice: lang on <html>, real <th scope> attributes, and explicit empty alt="" for decorative images. Skip any of these and you'll see warnings in PAC.
Generating compliant PDFs with Kamy
If you're using Kamy to render HTML to PDF, accessibility output is opt-in via flags on the request — the renderer maps your HTML structure to PDF tags and writes the required metadata:
bashcurl -X POST https://api.kamy.dev/v1/pdf \ -H "Authorization: Bearer $KAMY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "html": "<!doctype html><html lang=\"en-US\">...</html>", "options": { "tagged": true, "pdfua": true, "metadata": { "title": "Invoice INV-2025-0142", "author": "Acme Corp", "language": "en-US" } } }' \ --output invoice.pdf
The output includes the structure tree, XMP metadata with pdfuaid:part = 1, and DisplayDocTitle = true. You're still responsible for the HTML being semantically correct — no tool can infer that a <div> with bold text was supposed to be an <h2>.
Validating in CI
Don't trust the renderer. Validate every change to your template. The reliable options:
- veraPDF — open source, scriptable, supports PDF/UA-1.
- PAC 2024 — free, GUI-based, the most strict in practice.
A minimal CI check with veraPDF:
bashverapdf --flavour ua1 --format text invoice.pdf # exits non-zero on failure
Wire this into the same job that renders a