HTML to PDF
in Java.

The Java options are an old XHTML renderer, a library with a licence that makes legal nervous, or driving a browser yourself. A plain HttpClient call avoids all three.

The call

Post your markup with an API key. The PDF comes back in the same response, base64 encoded by default. Nothing is written to disk on our side.

GeneratePdf.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;

public class GeneratePdf {
    public static void main(String[] args) throws Exception {
        String payload = """
            {"html": "<h1>Invoice INV-1042</h1><p>Total: $1,645.40</p>",
             "responseFormat": "binary",
             "options": {"format": "A4", "printBackground": true}}
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.html4pdf.com/generate-pdf"))
            .header("Authorization", "Bearer " + System.getenv("HTML4PDF_KEY"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();

        HttpResponse<Path> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofFile(Path.of("invoice.pdf")));

        System.out.println("status " + response.statusCode() + ", wrote " + response.body());
    }
}

In Spring Boot

Return the bytes as a ResponseEntity and the browser downloads the file. Nothing is written to disk on your side.

InvoiceController.java
@GetMapping(value = "/invoices/{id}.pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> invoice(@PathVariable String id) throws Exception {
    String html = templateEngine.process("invoice", contextFor(id));

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.html4pdf.com/generate-pdf"))
        .header("Authorization", "Bearer " + apiKey)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(
            mapper.writeValueAsString(Map.of("html", html, "responseFormat", "binary"))))
        .build();

    byte[] pdf = HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofByteArray())
        .body();

    return ResponseEntity.ok()
        .header("Content-Disposition", "attachment; filename=\"" + id + ".pdf\"")
        .body(pdf);
}

What comes back

The default response is JSON with the document base64 encoded, the credits you have left, and how long the render took. Send responseFormat as binary instead and the body is the PDF itself, with a Content-Type of application/pdf.

200 OK
{
  "success": true,
  "pdf": "JVBERi0xLjQKJeLjz9MKMyAwIG9...",
  "creditsRemaining": 9,
  "metadata": { "size": 42813, "processingTime": 2841 }
}

A 402 means you are out of credits, a 401 means the key is wrong, and a 422 means the markup could not be rendered. Everything else is worth retrying once.

The usual Java libraries

Worth knowing before you add a dependency, because for a lot of documents one of these is the right answer and costs nothing.

LibraryWhat it isThe trade-off
Flying Saucer and openhtmltopdfRender well-formed XHTML with CSS 2.1 to PDF, in pure Java.No external dependencies and good typography. Your HTML must be valid XHTML, and modern CSS and JavaScript are out.
iTextThe most complete PDF toolkit on the JVM.Powerful, and dual licensed: AGPL, or a commercial licence if your product is not open source. Worth checking with legal before it reaches production.
Apache PDFBoxReads and writes PDFs at a low level.Great for manipulating existing files. It is not an HTML renderer.
Playwright or SeleniumDrive a real browser from Java and print to PDF.Accurate, but now you operate browsers next to your JVM.

Java: common questions

What is the best HTML to PDF library for Java?

openhtmltopdf if your markup is valid XHTML with simple CSS and you want zero services. iText if you need deep PDF features and can accept the licence. If the page is a modern web page, render it in a browser rather than reimplementing one.

Do I need an external dependency for the API call?

No. java.net.http.HttpClient has been in the JDK since Java 11. Jackson only appears in the Spring example for building JSON.

Is iText free to use?

It is AGPL, which means publishing your source or buying a commercial licence. That is the usual reason teams look elsewhere.

Can I stream the PDF directly to a file?

Yes. BodyHandlers.ofFile writes the response body to disk as it arrives, which is what the first example does.