I'm generating a PDF from a responsive web page (mobile version) using a headless Chrome instance and the Chrome DevTools Protocol (CDP) in Java. The goal is to produce a single-page PDF that reflects exactly what the user would see on a mobile screen.
My Setup:
- I launch headless Chrome in the terminal.
- I connect to it using the webSocketDebuggerUrl.
- I execute the following CDP commands in this order (all synchronously):
// Step 1: Enable required domains
send("Page.enable");
send("Runtime.enable");
send("Log.enable");
// Step 2: Set mobile viewport
send("Emulation.setDeviceMetricsOverride", {
width: 360,
height: 640,
deviceScaleFactor: 1,
mobile: true
});
// Step 3: Set media to screen
send("Emulation.setEmulatedMedia", {
media: "screen"
});
// Step 4: Navigate to the URL
send("Page.navigate", {
url: "https://arunac97.github.io/samplesite.com/newcanvas.html"
});
// Step 5: Wait for the page to load (handled properly in code)
// Step 6: Get layout metrics
JSONObject layout = send("Page.getLayoutMetrics");
JSONObject cssContentSize = layout.getJSONObject("cssContentSize");
float contentWidth = cssContentSize.getFloat("width");
float contentHeight = cssContentSize.getFloat("height");
// Step 7: Print to PDF
send("Page.printToPDF", {
paperWidth: contentWidth / 96, (converting pixel to inch - 96 dpi)
paperHeight: contentHeight / 96,
marginTop: 0,
marginBottom: 0,
marginLeft: 0,
marginRight: 0,
scale: 1,
printBackground: true
});
Problem: The PDF is generated correctly, but it includes a large blank space at the bottom—about 30% of the page height—which shouldn't be there.
- I'm using Page.getLayoutMetrics to determine the real content size and feeding those exact values (converted to inches) into Page.printToPDF.
- I'm drawing a element using JavaScript after the page loads. The canvas is sized to exactly match the full scrollable width and height of the page and is positioned on top of all content.
If I use a custom paperWidth and paperHeight in printToPDF that doesn't exactly match the page's real dimensions, Chrome seems to re-render the page with those new dimensions during PDF generation. This causes the canvas to become misaligned or appear at the wrong place, since it was drawn based on the original page size.
That's why I'm using the exact width and height from Page.getLayoutMetrics to avoid this rendering issue and preserve the canvas position.
Questions: What causes this extra space to be appended to the bottom of the generated PDF?
- Is there a better way to determine the exact printable area without causing canvas misalignment?
- Is there any known workaround to force Page.printToPDF to honor only the actual visible content?
- Any help or insight would be deeply appreciated.
This is a test website I hosted on GitHub Pages to reproduce and test these cases: https://arunac97.github.io/samplesite.com/newcanvas.html
GitHub repo with reproducible code: https://github.com/arunac97/HeadlessApp (Contains Java code and the canvas-drawing JS.)
🧪 Test Cases:
Case 1 (multi-page, fixed dimensions): Canvas misaligns. https://github.com/arunac97/HeadlessApp/blob/main/case1.pdf
Case 2 (single tall page using getLayoutMetrics): Extra blank space at bottom. https://github.com/arunac97/HeadlessApp/blob/main/case2.pdf
Thanks!