Free tools Windows power users keep installed
One-click scans. No signup required.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Direct answer: treat PDF generation as four separate stages: validate and normalize the JSON, render it into HTML, compile SCSS into CSS, and pass the resulting HTML and CSS to a PDF renderer. Use Puppeteer or Playwright when the document depends on browser behavior or JavaScript; use WeasyPrint for a library-oriented HTML/CSS workflow. Both browser libraries use print CSS by default, so define print rules explicitly and test representative documents before production.
The four-stage pipeline
- Validate and normalize JSON. Apply a schema before rendering. Convert dates to one display format, normalize currency values, supply defaults for optional fields, and ensure repeated structures such as line items are arrays. Reject malformed or unexpected input before it reaches a template.
- Render semantic HTML. Use your application’s template engine to produce headings, paragraphs, tables and lists. Keep document structure independent from presentation so the same data can support HTML previews and PDFs.
- Compile SCSS to CSS. SCSS is not an input format for the PDF APIs described here. Compile it during your build or request pipeline, then embed the resulting CSS or make it available as a stylesheet.
- Render the PDF. Give the renderer finished HTML and CSS, configure paper and margins, wait for required resources, and write the PDF bytes to a file or response.
This separation also makes failures easier to diagnose: invalid data belongs to validation, missing content to templating, styling errors to SCSS compilation, and pagination or resource problems to the renderer.
Prepare JSON and render predictable HTML
Validate before templating
Define required fields and types with the schema tool used by your application. Normalize values once, rather than adding formatting logic throughout the template. For example, convert an ISO date to the intended locale, round monetary amounts according to your accounting rules, and turn missing optional values into an empty string or an explicit “not provided” label.
Escape untrusted values
Use the escaping mode supplied by your template engine. Never concatenate user-provided HTML into a document unless your sanitizer and security policy explicitly allow it. A PDF renderer processes markup and may load external resources, so treat templates, CSS, URLs and embedded data as input that requires the same controls as a web page.
#1 Best Overall
Keep the markup print-friendly
Prefer semantic elements and simple layout primitives. Give tables a header row, keep related content together where possible, and provide meaningful alternate text for images. Avoid relying on a screen-only interaction that has no printed equivalent.
Compile SCSS and add print rules
Run your normal SCSS compiler to produce CSS before invoking Puppeteer, Playwright or WeasyPrint. The renderer receives CSS, not SCSS source. You can link a generated stylesheet, inline it, or inject it through the renderer API.
Put document-specific rules in a print layer. Typical rules include:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
@pagesize and margins.- Page-break behavior for headings, cards and table rows.
- Repeated table headers where your engine supports them.
- Print-only and screen-only variants.
- Color and background behavior for branded documents.
Browser PDF generation uses the print media type by default. Puppeteer documents the default as “Generates a PDF of the page with the print CSS media type” (Puppeteer Page.pdf()); Playwright documents the same behavior in its Page API. If your design was written only for screen media, either add print styles or deliberately emulate screen media before generating the file.
Exact colors may be adjusted for printing. Where color fidelity matters, test the target browser and consider -webkit-print-color-adjust: exact; in the print stylesheet, as described in the Puppeteer and Playwright documentation.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Choose a renderer
| Decision axis | Puppeteer or Playwright | WeasyPrint |
|---|---|---|
| Rendering model | Creates a PDF from a browser page. Print media is the default. | Builds HTML/CSS objects and writes the rendered document to PDF. |
| JavaScript and browser behavior | Appropriate when the page depends on browser layout or JavaScript; test the exact page. | Library-oriented HTML/CSS flow; it is not a drop-in browser runtime. |
| Screen versus print | Call media emulation for screen styling; otherwise provide print CSS. | Supply print-oriented CSS and use @page rules where supported. |
| Document controls | Puppeteer documents paper format and header/footer options; verify the installed API version. | Use HTML/CSS objects, stylesheets and documented page-layout features. |
There is no universal winner established by the official documentation. Validate your own pages, fonts, images, tables, JavaScript and pagination. Puppeteer’s PDF options reference is identified as version 25.12.0, so recheck option names against the version installed in your project.
Node.js with Puppeteer
The following example shows the application stages. Replace the placeholder functions with your schema validator, template engine and SCSS compiler.
import puppeteer from 'puppeteer';
const data = validateAndNormalize(jsonInput);
const html = renderTemplate(data); // your template engine
const css = compileScss(scssSource); // your SCSS compiler
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setContent(`<!doctype html>
<html><head><meta charset="utf-8">
<style>${css}</style></head>
<body>${html}</body></html>`,
{ waitUntil: 'networkidle0' });
await page.pdf({
path: 'invoice.pdf',
format: 'A4',
printBackground: true,
margin: { top: '18mm', right: '15mm', bottom: '18mm', left: '15mm' }
});
} finally {
await browser.close();
}
Use page.emulateMediaType('screen') before page.pdf() when you intentionally want screen media instead of the documented print default. Wait for fonts and images that are loaded after setContent; a network-idle condition alone may not cover resources created later by application JavaScript. Header and footer templates, paper formats and other options are documented in Puppeteer PDFOptions.
Node.js with Playwright
import { chromium } from 'playwright';
const data = validateAndNormalize(jsonInput);
const html = renderTemplate(data);
const css = compileScss(scssSource);
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.setContent(`<style>${css}</style>${html}`, {
waitUntil: 'networkidle'
});
// Optional: use screen CSS rather than the print default.
// await page.emulateMedia({ media: 'screen' });
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true,
margin: { top: '18mm', right: '15mm', bottom: '18mm', left: '15mm' }
});
} finally {
await browser.close();
}
Playwright’s page.pdf() and media-emulation behavior are described in its Page API. Pin and record the Playwright version used by your deployment, because browser binaries and API details change over time.
Python with WeasyPrint
WeasyPrint accepts HTML and CSS from strings, files, URLs or file-like objects. Its documented object workflow is concise:
Rank #3
from weasyprint import HTML, CSS
normalized = validate_and_normalize(json_data)
html_text = render_template(normalized)
css_text = compile_scss(scss_source)
document = HTML(string=html_text, base_url="/app/templates")
pdf_bytes = document.write_pdf(stylesheets=[CSS(string=css_text)])
with open("report.pdf", "wb") as output:
output.write(pdf_bytes)
Read WeasyPrint First Steps for input and output forms. Its project documentation discusses @page and feature limitations in Common Use Cases. The result depends on the HTML, CSS and PDF features selected; do not assume complete browser-CSS parity.
Page layout that survives real data
Control page size and margins
Set paper size and margins in one place: renderer options for browser engines, and @page for CSS-driven layout where supported. Keep enough margin for headers, footers and printers that cannot print to the edge.
Handle long content
Test one-page and multi-page documents, very long names, unbroken URLs, large tables, missing fields and rows that split across pages. Add explicit break rules for sections that must start together, but avoid forcing every component onto a new page.
Load assets deterministically
Relative URLs, fonts and images depend on the HTML base URL and the renderer’s environment. Supply a correct base URL or absolute, permitted resource URLs. In containers, install the fonts your design requires and verify that the renderer can reach them.
Check colors, links and metadata
Open the produced PDF with more than one viewer. Check page count, font substitution, hyperlinks, selectable text, bookmarks where required, color output and document metadata. If you need accessibility or archival conformance, validate those requirements with dedicated tooling; the renderer documentation does not guarantee a particular conformance level.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Security and reliability
- Do not render untrusted HTML or CSS with unrestricted filesystem or network access. The WeasyPrint guidance warns that untrusted content can expose local resources; restrict resource loading and validate inputs.
- Apply timeouts around browser startup, navigation, font loading and PDF generation. Close pages and browsers in a
finallyblock. - Make jobs idempotent. Store the normalized input and renderer version so a failed document can be reproduced.
- Limit document size, image dimensions and repeated-item counts to prevent memory exhaustion.
- Run representative visual regression tests after changing templates, SCSS, browser versions or fonts.
Troubleshooting
The PDF uses the wrong colors or layout
Cause: print CSS is active by default. Add print rules, or call Puppeteer’s page.emulateMediaType('screen') or Playwright’s page.emulateMedia({ media: 'screen' }) before PDF generation. Also check printBackground and color-adjust rules.
Images or fonts are missing
Cause: inaccessible relative URLs, an incorrect base URL, blocked network access or fonts unavailable in the runtime. Use a valid base URL, permit only required resources, wait for loading, and install or embed the intended fonts.
Content is clipped or unexpectedly split
Cause: fixed heights, oversized elements, table rows or page-break rules. Remove rigid heights, inspect the computed print CSS, and test long values and multi-page tables.
JavaScript-generated content is absent
Cause: PDF generation began before the application finished rendering. Wait for a specific selector or application-ready signal, then capture. If the document does not need JavaScript, server-render the HTML before passing it to the renderer.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →WeasyPrint output differs from the browser
Cause: specialized HTML/CSS renderers do not implement every browser feature. Reduce browser-specific dependencies, consult the current WeasyPrint feature documentation, and choose a browser renderer when the page genuinely requires browser behavior.
Best Value
The process hangs or consumes too much memory
Cause: unbounded input, heavy images, stalled resources or leaked browser instances. Enforce limits and timeouts, optimize assets, block unnecessary requests, and always close renderer resources.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It can return PNG, JPEG, WebP or PDF from one request, while handling the browser infrastructure for you. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
For a direct PDF or image capture, see the ScreenshotNeo documentation. The same service supports full-page capture with lazy images, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, click and wait conditions, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture and a usage API. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account to get started.
Cost, performance and operations
Browser renderers require a browser process and are usually best operated with controlled concurrency, reused browser instances and bounded page lifetimes. WeasyPrint avoids browser automation but still needs limits for large HTML, images and fonts. Measure your own representative documents rather than assuming one engine is faster or more faithful. Cache compiled CSS and templates, but invalidate caches when data, assets or styles change. For repeated captures, a renderer-level cache or ScreenshotNeo’s configurable TTL can reduce duplicate work.
Verification checklist
- Schema validation rejects malformed JSON and normalizes optional values.
- HTML contains all expected records, escaped values and accessible labels.
- SCSS compilation succeeds and the PDF receives the generated CSS.
- Print or screen media is intentionally selected.
- Fonts, images, links, colors and page breaks are checked in the final PDF.
- Long text, empty arrays, missing images, special characters and multi-page tables are covered by tests.
- Timeouts, resource restrictions, cleanup and reproducible versioning are in place.
Frequently Asked Questions
Can a PDF renderer compile SCSS directly?
No. Compile SCSS to CSS in your application or build pipeline, then provide the CSS to the renderer.
Which renderer should I use for JavaScript-heavy pages?
Start with Puppeteer or Playwright because they render through a browser, then test the exact page and browser version. Use WeasyPrint when your document fits its HTML/CSS feature set and does not require browser JavaScript.
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 →Why does my screen design change in the PDF?
Puppeteer and Playwright use print CSS by default. Add print styles or explicitly emulate screen media before calling the PDF method.
How do I protect a PDF service that accepts user HTML?
Validate and sanitize inputs, restrict filesystem and network resource access, enforce size and time limits, and do not render untrusted content with unrestricted privileges.
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.

