WeasyPrint pdf_variant — PDF/A and PDF/UA Reference
WeasyPrint can emit PDF files that conform to the PDF/A archival standards and the PDF/UA accessibility
standard. Which one you get is controlled by a single argument, pdf-variant. This page documents
every value that argument accepts, what each conformance level actually guarantees, and what your HTML must
contain for the output to be valid.
PdfBroker.io runs WeasyPrint as a hosted REST API, so the same argument is available without installing
WeasyPrint, Pango, or any font tooling locally. Everything below applies both to the WeasyPrint command line
(--pdf-variant) and to the weasyPrintToPdfArguments object in a PdfBroker.io API
request.
Syntax
In a PdfBroker.io API request, pdf-variant is a key inside weasyPrintToPdfArguments:
{
"htmlBase64String": "PCFET0NUWVBFIGh0bWw...",
"weasyPrintToPdfArguments": {
"pdf-variant": "pdf/a-2b"
}
}
The equivalent on the WeasyPrint command line:
weasyprint --pdf-variant pdf/a-2b input.html output.pdf
The value is lowercase and includes the slash. Only one variant can be requested per document. If a file must be
both archival and accessible, that is a single variant too — see
combining PDF/A and PDF/UA below. An unrecognised value is rejected with a
400 Bad Request; the list under accepted values is exhaustive.
Accepted values
| Value | Standard | Based on | Use it for |
|---|---|---|---|
pdf/a-1b |
PDF/A-1b (ISO 19005-1) | PDF 1.4 | The most conservative and most widely accepted archival level. Choose this when an authority specifies "PDF/A" without a version, or when the receiving system is old. |
pdf/a-2b |
PDF/A-2b (ISO 19005-2) | PDF 1.7 | The common default for new archival work. Adds JPEG2000, transparency, and layers over A-1b, and allows PDF/A files to be embedded inside one another. |
pdf/a-3b |
PDF/A-3b (ISO 19005-3) | PDF 1.7 | Identical to A-2b except that arbitrary files may be embedded. This is the level used for electronic invoicing formats that carry a machine-readable XML payload inside the PDF. |
pdf/a-2u |
PDF/A-2u (ISO 19005-2) | PDF 1.7 | Level B plus a guarantee that all text maps to Unicode, so the document can be searched and copied reliably. A cheap upgrade over A-2b when the archive is meant to be read, not just stored. |
pdf/a-3u |
PDF/A-3u (ISO 19005-3) | PDF 1.7 | A-3b with the same Unicode guarantee. The usual choice for e-invoicing profiles that require both an embedded XML payload and extractable text. |
pdf/a-1a |
PDF/A-1a (ISO 19005-1) | PDF 1.4 | Level A: everything level B guarantees, plus a tagged structure tree and Unicode mapping. Archival and accessible in one file. |
pdf/a-2a |
PDF/A-2a (ISO 19005-2) | PDF 1.7 | The practical choice when a document must satisfy an archival policy and an accessibility requirement at the same time. |
pdf/a-3a |
PDF/A-3a (ISO 19005-3) | PDF 1.7 | Level A with embedded attachments allowed — an accessible e-invoice carrying its own XML. |
pdf/a-4u |
PDF/A-4 (ISO 19005-4) | PDF 2.0 | The baseline PDF/A-4 level. PDF/A-4 dropped the A/B lettering and requires Unicode mapping of all text, which is why the value carries a "u". Choose it only when the recipient has confirmed PDF 2.0 support — validator and reader coverage is still thinner than for A-2b. |
pdf/a-4f |
PDF/A-4f (ISO 19005-4) | PDF 2.0 | PDF/A-4 with arbitrary embedded files allowed. The PDF 2.0 successor to A-3b for e-invoicing. |
pdf/a-4e |
PDF/A-4e (ISO 19005-4) | PDF 2.0 | The engineering profile, intended for technical documentation carrying 3D and rich-media content. Rarely what a web document needs. |
pdf/ua-1 |
PDF/UA-1 (ISO 14289-1) | PDF 1.7 | Accessibility. Produces a tagged PDF with a semantic structure tree that screen readers can navigate. Relevant to the European Accessibility Act. This is the value to use unless a recipient has specifically asked for UA-2. |
pdf/ua-2 |
PDF/UA-2 (ISO 14289-2) | PDF 2.0 | The PDF 2.0 revision of PDF/UA. Same purpose, newer tag model. Tooling support is still catching up, so verify that your validator and your recipient handle it before switching. |
pdf/x-1a |
PDF/X-1a:2003 (ISO 15930-4) | PDF 1.4 | Print production. The most restrictive print exchange profile — CMYK or spot colour only, everything embedded. |
pdf/x-3 |
PDF/X-3:2003 (ISO 15930-6) | PDF 1.4 | Print production allowing colour-managed RGB in addition to CMYK. |
pdf/x-4 |
PDF/X-4 (ISO 15930-7) | PDF 1.6 | The modern print exchange profile: transparency and layers are preserved rather than flattened. Ask your printer which profile they want before choosing. |
pdf/x-5g |
PDF/X-5g (ISO 15930-8) | PDF 1.6 | X-4 extended with references to external graphic objects. Only for workflows that have explicitly asked for it. |
The letter at the end: a, b and u
PDF/A-1 through A-3 define conformance levels within each version. Level B (basic)
guarantees that the document will look the same in future — fonts embedded, colour spaces defined,
no external dependencies. Level U adds a guarantee that all text maps to Unicode.
Level A (accessible) adds a tagged structure tree on top of that. PDF/A-4 dropped the
lettering: it requires Unicode throughout, and the remaining profiles are f (embedded files)
and e (engineering).
There is no pdf/a-4b. Requesting it returns an error — use pdf/a-4u for
baseline PDF/A-4.
What your HTML must provide
Requesting a variant does not by itself make a document conformant. WeasyPrint handles the PDF-level mechanics — font embedding, colour space declaration, XMP metadata, the structure tree — but it can only work with what the HTML gives it. These are the requirements that fail most often in practice.
For all PDF/A variants
- Fonts must be embeddable. Every font used has to be embedded in full. Fonts with licence flags that forbid embedding will fail validation. Web-safe font stacks that fall back to a system font are a common cause — declare the font explicitly and supply it as a resource.
- No external references at render time. Images, stylesheets and fonts referenced by URL are fetched during rendering, but a network failure produces a silently incomplete document. Send images as Base64 resources instead.
- Transparency is not allowed in PDF/A-1b. CSS
opacity,rgba()colours, and PNGs with an alpha channel will break A-1b conformance. They are permitted from A-2b onward. - Document metadata. A
<title>element is required. Supply<html lang="...">as well — it is mandatory for PDF/UA and good practice everywhere.
Additionally for tagged output (pdf/ua-1, pdf/ua-2 and the level A variants)
- Semantic HTML throughout. The structure tree is generated from your markup.
<div>elements styled to look like headings produce an untagged document that passes nothing. Use real<h1>–<h6>,<p>,<ul>,<table>. - Heading hierarchy without gaps. Exactly one
<h1>, and no skipping from<h2>to<h4>. - Alt text on every image. An
altattribute is required on each<img>. Purely decorative images should carry an emptyalt=""so they are marked as artifacts rather than left untagged. - Table headers with scope. Use
<th scope="col">orscope="row"so cell relationships survive into the tag tree. - A language attribute.
<html lang="sv">or equivalent. Mark passages in another language withlangon the element. - Meaningful link text. "Read more" repeated twelve times is valid PDF/UA but fails the human review that usually accompanies a compliance audit.
Combining PDF/A and PDF/UA
A document that must be both archival and accessible — increasingly common for public-sector records in the
EU — is served by a single PDF/A level A variant. pdf/a-2a is the usual choice:
it claims PDF/A-2 conformance in the document metadata and emits the tagged structure tree that
accessibility rests on. Use pdf/a-3a instead when the file also carries an embedded attachment.
Level A output is only as good as the markup behind it, so the
PDF/UA requirements below apply in full: semantic elements, an unbroken heading
hierarchy, alt text, table scopes, a language attribute. If the requirement is a formal PDF/UA claim rather than an
archival one, request pdf/ua-1 and write the HTML to satisfy the PDF/A rules as well —
embeddable fonts, no external references, complete metadata. Validate against your specific requirement either
way; the two standards overlap but neither implies the other.
Examples
C# with PdfBroker.Client
// Install: dotnet add package PdfBroker.Client
using PdfBroker.Client;
var client = new PdfBrokerClientService("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET");
var html = File.ReadAllText("invoice.html");
var htmlBase64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(html));
byte[] pdf = await client.WeasyPrintAsByteArrayAsync(new
{
htmlBase64String = htmlBase64,
weasyPrintToPdfArguments = new Dictionary<string, string>
{
["pdf-variant"] = "pdf/a-3b"
}
});
await File.WriteAllBytesAsync("invoice.pdf", pdf);
Python
import base64, requests
token = requests.post("https://login.pdfbroker.io/connect/token", data={
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
}).json()["access_token"]
html = open("report.html", "rb").read()
resp = requests.post(
"https://api.pdfbroker.io/api/pdf/weasyprint",
headers={"Authorization": "Bearer " + token},
json={
"htmlBase64String": base64.b64encode(html).decode(),
"weasyPrintToPdfArguments": {"pdf-variant": "pdf/ua-1"},
},
)
open("report.pdf", "wb").write(resp.content)
cURL
HTML_BASE64=$(base64 -w0 document.html)
curl -X POST https://api.pdfbroker.io/api/pdf/weasyprint \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"htmlBase64String\": \"$HTML_BASE64\",
\"weasyPrintToPdfArguments\": { \"pdf-variant\": \"pdf/a-2b\" }
}" \
--output document.pdf
Verifying the output
Do not assume conformance because the request succeeded. Validate the file with a tool that PdfBroker.io does not control.
- veraPDF — the open source reference validator for PDF/A and PDF/UA, developed by the Open Preservation Foundation together with the PDF Association — the same people who maintain the ISO standards. Command line and desktop. This is the tool most auditors use.
- PAC (PDF Accessibility Checker) — free Windows tool from axes4 for PDF/UA and WCAG, with a screen reader preview and a visual view of the tag tree that makes structural problems obvious.
- Adobe Acrobat Pro — its preflight profiles cover PDF/A and its accessibility checker covers much of PDF/UA.
Validators disagree more often than you would expect — the same document can pass one and fail another, because each interprets parts of the ISO text differently. For anything going into a compliance review, run at least two.
A useful habit is to run veraPDF in CI against a representative document from each template. Conformance breaks quietly — a designer swapping in a new font is enough.
Common failures
- Validation fails on font embedding
- A font in the CSS stack was not available and a substitute was used, or a font's licence forbids embedding. Declare fonts explicitly and supply them as resources rather than relying on the rendering host.
- Transparency errors on
pdf/a-1b - Remove
opacity,rgba()and alpha-channel images, or move topdf/a-2b, which permits them. - PDF/UA validation reports untagged content
- Content produced by CSS
::beforeand::after, or laid out with positioned<div>elements, may not map to a semantic tag. Rewrite the affected region with real elements. - The request fails with
400 Bad Request - The variant value is not one the engine recognises.
pdf/a-4bis the common case — it is not a real conformance level, since PDF/A-4 dropped the A/B lettering. Usepdf/a-4u, or pick a value from accepted values. - The document renders but ignores
pdf-variant - Check spelling and case — the key is
pdf-variant, the value is lowercase with a slash, and it belongs insideweasyPrintToPdfArguments, not at the top level of the request. - JavaScript-generated content is missing
- WeasyPrint does not execute JavaScript. Render dynamic content server-side before sending the HTML. If you need JavaScript, use the wkhtmltopdf service — but note that it cannot produce PDF/A or PDF/UA output.