The journal · 19 July 2026 · 10 min read
HTML to PDF in Java: the libraries that work, and their catches
Java has three real ways to turn HTML into a PDF: a pure Java engine like OpenHTMLtoPDF, the commercial iText pdfHTML, or a real browser via Playwright or an API. Each has a catch, CSS limits, an AGPL license, or an infrastructure bill. Here is the current map with code.
Java has been generating PDFs for two decades, so the ecosystem is deep and a little confusing. When you actually try to convert HTML to PDF, the options collapse into three families: a pure Java rendering engine like OpenHTMLtoPDF or Flying Saucer, the commercial iText pdfHTML converter, or driving a real browser through Playwright, Selenium or a hosted API. Each family produces very different output, and each carries a catch you should know before you commit: a CSS ceiling, a licensing bill, or an infrastructure one. Here is the current map for 2026, with working code and the tradeoffs that actually decide it.
The short version
If your template is simple and controlled, a pure Java library like OpenHTMLtoPDF renders it with no external dependencies, but it only supports roughly CSS 2.1, so no flexbox, grid or JavaScript. If you need modern CSS inside pure Java, iText pdfHTML supports flexbox and grid, but it is AGPL v3, which means you either open source your whole application or buy a commercial license that starts around five figures a year. If the PDF has to match a real browser exactly, you need a browser: Playwright for Java driving headless Chrome, self hosted Gotenberg, or a hosted rendering API that runs the browser for you. Pick the family by how faithful the output must be and what license and infrastructure you can live with.
OpenHTMLtoPDF: the maintained pure Java pick
OpenHTMLtoPDF is the practical default when you want a pure Java library. It is a modern successor to Flying Saucer, renders a well formed subset of XHTML and HTML5 using CSS 2.1 for layout, and writes the result to PDF using Apache PDFBox rather than iText. The actively maintained fork at io.github.openhtmltopdf has moved to PDFBox 3, and it does a few things that matter for documents: SVG images, and accessible tagged PDF output for WCAG, Section 508 and PDF/UA. It is licensed LGPL, so you can use it in proprietary software without open sourcing your app.
// build.gradle: implementation 'io.github.openhtmltopdf:openhtmltopdf-pdfbox:1.1.+'
try (var os = new FileOutputStream("invoice.pdf")) {
var builder = new PdfRendererBuilder();
builder.useFastMode();
builder.withHtmlContent(xhtml, baseUri); // xhtml must be well formed
builder.toStream(os);
builder.run();
}
The one hard requirement is in that comment: the input must be well formed XHTML. OpenHTMLtoPDF will not swallow the tag soup a browser tolerates, so you usually run your HTML through a cleaner like jsoup first. The bigger limit is the CSS ceiling. The engine is CSS 2.1 with some later additions, which means flexbox and CSS grid are not supported and there is no JavaScript at all. For an invoice, a statement or a certificate that you design with those constraints in mind, it is fast, free and produces clean, accessible PDFs. For a template lifted from a modern responsive web page, columns will collapse and script driven content will be blank.
Flying Saucer: the older cousin
Flying Saucer is the library OpenHTMLtoPDF grew out of. It renders XML and XHTML with CSS 2.1 to PDF, images or a Swing panel, and it still shows up in older projects and tutorials. Two things are worth knowing. First, it depends on iText version 2, which is LGPL, so the licensing is friendlier than modern iText but the underlying PDF library is very old. Second, for new work there is little reason to choose it over OpenHTMLtoPDF, which is its maintained descendant with a current PDFBox backend, SVG and accessibility support. If you are on Flying Saucer today and hitting bugs, migrating to OpenHTMLtoPDF is usually the shortest path, because the CSS model is the same.
iText pdfHTML: the most capable, with a licensing catch
iText pdfHTML is the most powerful pure Java HTML to PDF converter. Unlike the CSS 2.1 engines, it has kept adding modern layout: comprehensive flexbox support arrived in 2025, CSS grid in 2024, and it handles CSS paged media headers and footers and can even convert HTML forms to AcroForm fields. If you need modern CSS but cannot run a browser, it is the strongest option in the language.
The catch is the license, and it is a big one. iText is AGPL v3. That means if you distribute your application or expose it over a network, the AGPL requires you to release your entire application source under a compatible license. For most commercial products that is a non starter, so you buy a commercial license instead, and iText commercial licensing is enterprise priced, commonly ranging from roughly ten thousand dollars a year into the six figures depending on scale. None of that is hidden or unfair, but teams are regularly surprised by it after they have built on the library, so decide the license question before you write the integration, not after.
// With a commercial or AGPL-compliant setup:
try (var os = new FileOutputStream("report.pdf")) {
HtmlConverter.convertToPdf(html, os); // com.itextpdf:html2pdf
}
When the PDF has to match a real browser
The pure Java engines share one boundary: none of them is a browser, so none runs JavaScript or renders modern CSS the way Chrome does. When the output must match a browser exactly, charts drawn by a script, a layout built with flexbox and grid, web fonts loaded at runtime, you need an actual browser engine in the loop, and there are three ways to get one.
The first is to drive it yourself. Playwright for Java (or Selenium) launches headless Chrome, loads your page, and calls Chrome's own print to PDF. The fidelity is perfect because Chromium is doing the rendering. The cost is that you are now running a browser in a JVM shop: installing and patching Chrome on every host and container, and absorbing the reality that headless Chrome leaks memory and falls over under concurrency, so you end up pooling browser instances and queuing work. The library versus API comparison lays out that operational bill in detail, and the Puppeteer alternative page covers the same tradeoff from the browser automation side.
The second is to self host a rendering service. Gotenberg is a popular Docker container that wraps Chromium behind an HTTP API, which keeps the browser out of your JVM but still leaves you operating and scaling a container. The third is to let someone else run the browser entirely.
A hosted API: one call, no browser to run
A hosted rendering API runs managed Chromium on its own infrastructure, so from Java it is one HTTP request. You send a URL or your rendered HTML and get back a PDF that matches the browser, with no Chrome to install, no pool to tune and nothing to patch. Java's built in HttpClient makes the call trivial.
var client = HttpClient.newHttpClient();
var form = "url=" + URLEncoder.encode("https://example.com/report/8842", UTF_8)
+ "&format=Letter&archive=true";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sitepdf.com/v1/render"))
.header("Authorization", "Bearer " + System.getenv("SITEPDF_KEY"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
The archive=true parameter is the part a library cannot give you. It tells the renderer to store a timestamped snapshot of exactly what it rendered, retrievable later by id. For finance, legal and compliance workflows that need to prove what a document looked like when it was produced, that dated record is often the deciding feature. The full call shape is covered on the PDF generator API page, and if you are on Spring Boot specifically, the Spring Boot HTML to PDF page has the Thymeleaf render and the WebClient call together.
Which should you pick
| Situation | Best fit |
|---|---|
| Simple, controlled templates, pure Java, free, LGPL | OpenHTMLtoPDF |
| Modern CSS (flexbox, grid) without a browser, license budget available | iText pdfHTML |
| Output must match Chrome exactly, you can run a browser | Playwright for Java or self hosted Gotenberg |
| Browser fidelity with no infrastructure, plus a dated archive | Hosted rendering API |
| Programmatic layout, no HTML at all | PDFBox or OpenPDF directly |
Most Java teams start with OpenHTMLtoPDF because it is free and pure Java, then hit one of two walls: the CSS ceiling or, if they reach for iText to break through it, the AGPL license. At that point the honest question is whether running a browser belongs in your stack at all. If it does, Playwright or Gotenberg give you full fidelity that you operate. If it does not, a hosted API gives you the same Chromium output without the browser, which is why so many JVM shops end up calling one for their high volume rendering.
One more thing worth planning for: PDFs are a two way street. The same vendors who send you invoices as PDFs are documents you will eventually need to read back into structured data, and pulling fields out of a scanned or generated PDF is a completely different job from producing one, closer to enterprise document data extraction than to rendering. Keep the two directions separate in your architecture and each stays simple.
The bottom line
There is no single best HTML to PDF library in Java, only the right family for your constraints. Pure Java engines like OpenHTMLtoPDF are free and dependency light but capped at CSS 2.1. iText pdfHTML breaks that ceiling but brings an AGPL license and enterprise pricing. Real browser paths, Playwright, Gotenberg or a hosted API, give you exact fidelity, with the only question being who runs the browser. Decide the license and infrastructure questions first, and the library choice follows almost automatically. If keeping a browser out of your deployment is a hard constraint, HTML to PDF without headless Chrome compares the pure-code and hosted routes directly, and the C# guide covers the same decision on the other big enterprise runtime.
Written by the team building Sitepdf, an HTML to PDF API that archives every page it renders. The in-browser converter is free to try; early access locks the launch pricing.