Free tools Windows power users keep installed
One-click scans. No signup required.
Use a real browser when the HTML depends on JavaScript. In Java, Playwright is the most direct general solution: open the page, wait for the application-specific content to appear, then call page.pdf(). A library such as OpenHTMLtoPDF is suitable only when your input is controlled, well-formed HTML that fits its supported CSS subset, because it does not execute JavaScript. Adobe PDF Services also documents a data-driven workflow in which JavaScript updates the DOM before conversion.
Choose the renderer before you write code
“Dynamic HTML” normally means that the browser receives an initial document and client-side JavaScript adds, replaces, or formats the content. The crucial distinction is whether JavaScript must run during conversion.
| Approach | Best fit | Important limitation |
|---|---|---|
| Playwright Java | Live sites, single-page applications, and templates using browser JavaScript or modern CSS | You must manage browser startup, page readiness, and print styling deliberately. |
| OpenHTMLtoPDF | Controlled XHTML or limited HTML generated by your application | It does not run JavaScript and does not implement many modern standards, including flex and grid. |
| Adobe PDF Services Java SDK workflow | Data-driven templates where supplied data and JavaScript update the DOM | The documented sample establishes the workflow, not current pricing, service limits, or a universal performance advantage. |
For an existing web page or a client-rendered application, start with Playwright. For an invoice or report whose markup is intentionally constrained, evaluate OpenHTMLtoPDF. Select the Adobe route when your architecture already uses that service and its documented template workflow fits your requirements.
Convert a JavaScript-rendered page with Playwright Java
1. Add Playwright and launch a browser
Install the Playwright Java dependency using the version approved by your project, then install the browser binaries required by that version. Keep browser installation in your build or deployment process rather than assuming a workstation already has a compatible browser.
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.options.LoadState;
import java.nio.file.Paths;
public class DynamicHtmlToPdf {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().setHeadless(true));
Page page = browser.newPage();
page.navigate("https://example.com/dashboard",
new Page.NavigateOptions().setWaitUntil(LoadState.DOMCONTENTLOADED));
// Replace this with a selector or application signal that means
// the required data is actually visible.
page.locator("[data-report-ready]").waitFor();
page.pdf(new Page.PdfOptions()
.setPath(Paths.get("report.pdf"))
.setFormat("A4")
.setPrintBackground(true)
.setMargin(new Page.PdfOptions.Margin()
.setTop("16mm")
.setRight("14mm")
.setBottom("16mm")
.setLeft("14mm")));
browser.close();
}
}
}
page.navigate() gets the document through the navigation lifecycle; it does not prove that asynchronous API calls have finished. Wait for a condition that belongs to your application: a report-ready element, a completed table, a status attribute, or another explicit signal. Do not replace that signal with an arbitrary delay unless the page provides no better contract.
2. Control media and page geometry
Playwright generates PDFs using print CSS media by default. If the page’s design is defined for screens, emulate screen media before printing:
page.emulateMedia(new Page.EmulateMediaOptions().setMedia(Media.SCREEN));
Use print media when you want the document’s @media print rules. The PDF options let you choose a paper format or explicit width and height, margins, background graphics, and whether CSS @page size should be honored. A typical print configuration is:
page.pdf(new Page.PdfOptions()
.setPath(Paths.get("report.pdf"))
.setFormat("A4")
.setPreferCSSPageSize(true)
.setPrintBackground(true)
.setDisplayHeaderFooter(true)
.setHeaderTemplate("")
.setFooterTemplate(" / "));
Header and footer templates have their own rendering rules and should be tested with the fonts and page margins used in production. If your stylesheet defines page dimensions, setPreferCSSPageSize(true) prevents the selected paper format from unexpectedly overriding them.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors3. Make the HTML deterministic before capture
- Wait for the selector that identifies complete content, not merely for the first paint.
- Use a known viewport and, when necessary, a device scale factor so line wrapping is repeatable.
- Set authentication, cookies, or headers before navigation when the page is protected.
- Disable animations or pause them in print CSS if they can change the captured frame.
- Load fonts and images before printing; missing fonts can alter pagination.
page.addStyleTag(new Page.AddStyleTagOptions().setContent("""
*, *::before, *::after { animation: none !important; transition: none !important; }
@media print { .screen-only { display: none !important; } }
"""));
OpenHTMLtoPDF for controlled static documents
OpenHTMLtoPDF runs inside the JVM and is appropriate when your application generates well-formed XML/XHTML or limited HTML and CSS that the renderer supports. It explicitly does not run JavaScript and does not implement many modern standards such as flex and grid. Consequently, a page that fills a table through fetch(), mounts a React component, or relies on browser layout will not be reproduced merely by passing its source HTML to this library.
Rank #2
Use it when you can render all values server-side and keep the stylesheet within its supported subset. Validate the output with representative documents containing long text, page breaks, images, fonts, right-to-left text, and tables. If the source is modern web markup, first produce a renderer-compatible XHTML document rather than assuming a browser page will work unchanged.
When this option is a poor fit
- Client-side JavaScript is required to create the content.
- Your layout depends on CSS grid, flexbox, or other browser-only behavior.
- You need pixel-level parity with a live website.
- The page uses browser APIs that a JVM layout engine does not provide.
Adobe PDF Services dynamic-HTML workflow
Adobe’s Java SDK samples document a different pattern for dynamic HTML: provide data, let JavaScript update the HTML DOM, and then convert the resulting document to PDF. This can suit a controlled template pipeline in which the data contract and script are part of the application.
Treat the sample as evidence that the workflow exists, not as evidence of current pricing, quotas, throughput, or comparative performance. Confirm those operational details in the service documentation and your account terms before committing to it. You still need deterministic templates, validation of the resulting DOM, and error handling around network and service failures.
Waiting correctly: navigation versus application readiness
Navigation events describe browser lifecycle milestones. They are useful boundaries, but they are not a universal “data is ready” rule. A page can finish loading while an API request is still pending, or it can continue opening connections that make a network-idle heuristic unsuitable.
Prefer an explicit readiness contract
- Have the application add a stable attribute such as
data-report-ready="true"after required data and images are present. - Wait for that selector with a timeout appropriate to your environment.
- On timeout, save a diagnostic screenshot and page HTML, then fail the job instead of silently producing an incomplete PDF.
page.locator("[data-report-ready='true']").waitFor(
new Locator.WaitForOptions().setTimeout(30_000));
If you cannot change the page, wait for a distinctive result element and verify its text or count. A fixed delay is a last resort because it is either wasteful on fast runs or insufficient on slow ones.
Output quality, performance, and reliability
Browser lifecycle
Launching a browser for every document adds overhead. For a service that handles multiple jobs, keep one controlled browser process and create isolated contexts or pages per job, while enforcing limits and closing pages reliably. Do not let unbounded concurrent pages exhaust memory.
Fonts, assets, and network failures
PDF generation can fail or look wrong when a font, image, stylesheet, or API response is unavailable. Serve assets from stable URLs, provide authentication explicitly, and log the final URL and browser console errors. For reproducibility, pin browser and Playwright versions together and test after upgrades.
Pagination
Test long tables and repeated headers, not just a one-page example. Use print CSS for page breaks and avoid placing essential content inside elements whose height changes after printing. Compare PDFs in automated checks where document fidelity matters.
Security
Never pass untrusted URLs to a screenshot service or browser worker without an SSRF policy. Restrict outbound access, validate schemes, and isolate credentials. Treat HTML and JavaScript as executable input when the source is not fully controlled.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting common failures
The PDF contains an empty shell
Cause: conversion happened before client-side rendering completed. Fix: wait for an application-specific selector or state, and capture diagnostics on timeout.
Rank #4
Styles look different from the browser
Cause: PDF output uses print media by default, or print CSS hides or changes elements. Fix: inspect @media print rules and call emulateMedia() with screen media only when that is the intended design.
Flex or grid layout disappears with OpenHTMLtoPDF
Cause: those modern layout standards are outside the renderer’s documented implementation. Fix: simplify the template to supported CSS or switch to a browser renderer.
Navigation times out
Cause: slow, blocked, or continuously active resources. Fix: identify the blocking request, set a justified timeout, and wait on a specific readiness signal rather than assuming network idle.
Fonts or images are missing
Cause: inaccessible assets, incorrect relative URLs, or font loading that has not completed. Fix: verify asset responses in logs, use absolute or correctly based URLs, and test the production network path.
Pages break at unexpected locations
Cause: print dimensions, margins, font metrics, or late layout changes differ from development. Fix: set paper and margins explicitly, stabilize fonts and content, and test multi-page fixtures.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Best Value
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, and other MCP clients request captures.
For a PDF, call the API with the target URL:
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-d output=pdf
-o page.pdf
See the ScreenshotNeo documentation for PDF paper size, margins, landscape mode, page ranges, waits, authentication, custom JavaScript, and other options. Free accounts include 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Can Java convert HTML to PDF without a browser?
Yes, when the document is static and fits a library such as OpenHTMLtoPDF. It cannot execute the JavaScript needed by a client-rendered page.
Should I wait for network idle?
Not automatically. Use a page-specific readiness signal; network-idle behavior varies by application and open connections.
Why is my PDF in print colors and layout?
Playwright’s PDF API uses print media by default. Emulate screen media when the screen stylesheet is the intended source.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

