Recommended Free Tools
Use a document renderer in Python, then use GitHub Projects to manage the implementation. For CSS-focused reports, WeasyPrint is the shortest path: HTML(filename="report.html").write_pdf("report.pdf"). If your page depends on browser JavaScript or browser-only layout, use Playwright and its page.pdf() API instead. GitHub Projects does not render HTML or create PDFs; it organizes the issues, decisions, tests and documentation around your converter.
Choose the renderer before you create the project
The right library depends on what “HTML” means in your application. A static report with conventional CSS is a good WeasyPrint candidate. A page that must execute JavaScript, use browser APIs or match Chromium’s layout should be tested with Playwright.
| Concern | WeasyPrint | Playwright |
|---|---|---|
| Rendering model | HTML/CSS document renderer | Real browser page and print pipeline |
| Python API | HTML(...).write_pdf(...) |
page.pdf() |
| Environment | Python package plus operating-system libraries such as Pango; requirements vary by platform | Python package plus browser binaries |
| Media behavior | CSS is interpreted by WeasyPrint’s document engine | page.pdf() uses print media by default; call page.emulate_media(media="screen") when screen styles are required |
| Best first test | Representative CSS, fonts, images and page breaks | Representative JavaScript, network-loaded assets and browser-specific layout |
Neither choice is universally faster or more faithful. Render a representative document, not just a toy page, before committing to one.
Prepare a reproducible Python environment
WeasyPrint prerequisites
The current WeasyPrint first-steps documentation lists Python 3.10 or later and dependencies including Pango, pydyf, CFFI, tinyhtml5, tinycss2, cssselect2, Pyphen, Pillow and fontTools. Operating-system packages differ, so follow the current installation instructions for your platform rather than assuming that pip installs every native dependency.
#1 Best Overall
python -m venv .venv
# macOS/Linux
. .venv/bin/activate
# Windows PowerShell
# .venvScriptsActivate.ps1
python -m pip install --upgrade pip
python -m pip install weasyprint
weasyprint --info
weasyprint --info is a useful environment check. Commit a short setup note to the repository so another contributor can reproduce the same prerequisites.
Playwright prerequisites
python -m venv .venv
. .venv/bin/activate
python -m pip install playwright
playwright install chromium
The package and browser installation are separate steps. In CI, install the browser in the job that performs conversion and cache it only when your runner policy permits that.
Convert a local HTML file with WeasyPrint
Minimal conversion
This is the smallest useful implementation documented by WeasyPrint:
from weasyprint import HTML
HTML(filename="report.html").write_pdf("report.pdf")
Run it with python convert.py. A successful run writes report.pdf in the current directory. Treat the output path as an explicit build artifact rather than silently overwriting a production document.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use a string and make relative assets resolve
When HTML is generated by Python, pass a string and set a base URL so relative stylesheets, images and fonts have a known origin.
Rank #2
from pathlib import Path
from weasyprint import HTML
html = Path("templates/report.html").read_text(encoding="utf-8")
HTML(string=html, base_url=str(Path("templates").resolve())).write_pdf("build/report.pdf")
Create the build directory before writing it, and use UTF-8 consistently. If you pass a URL instead, confirm that every asset is reachable from the conversion environment; a browser that can reach an asset on your laptop may not be able to reach it in CI.
Control paper size, orientation and margins with CSS
@page {
size: A4 portrait;
margin: 2cm;
}
@page landscape-report {
size: A4 landscape;
margin: 1.5cm;
}
.landscape-page {
page: landscape-report;
}
h1, h2 {
break-after: avoid;
}
table, figure {
break-inside: avoid;
}
WeasyPrint documents @page as the control for page format, orientation and margins. Keep print-specific rules in a dedicated stylesheet and inspect the PDF at the target paper size; a layout that looks correct on screen can still produce an orphaned heading or an unwanted table split.
Generate from an HTTP page
from weasyprint import HTML
HTML(url="https://example.com/report").write_pdf("report.pdf")
Remote conversion introduces network and trust boundaries. Prefer a local, versioned template for deterministic builds. If you must fetch remote content, set timeouts and allow only the hosts your application needs at the surrounding application or network layer.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use Playwright when a browser engine is required
Playwright’s Python API starts a browser, loads the page and creates a PDF. The PDF operation uses print CSS media by default.
from pathlib import Path
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("file:///" + str(Path("report.html").resolve()), wait_until="networkidle")
page.pdf(path="report.pdf", format="A4", print_background=True)
browser.close()
For an HTTP page, replace the file:///... URL with the page URL. If the design is written for screen media, emulate it before calling page.pdf():
page.emulate_media(media="screen")
page.pdf(path="report.pdf", format="A4", print_background=True)
Wait for the condition that actually means “ready”: a selector, an application-specific completion flag or network idle. Network idle alone may be insufficient for pages that render after a background task.
Make the converter testable
Keep a small fixture and a representative fixture
- Minimal fixture: headings, paragraphs and one page break to detect a broken installation.
- Representative fixture: your real fonts, images, long tables, links, lists and any JavaScript-driven content.
- Failure fixture: a missing image, an unreachable URL and an intentionally long table so error handling is visible.
Check output properties
- Assert that the PDF file exists and is larger than zero bytes.
- Open it with a PDF parser in tests and verify the expected page count or text, rather than relying only on a successful process exit.
- For visual regressions, store a reviewed baseline or render pages to images and compare them with a deliberately chosen tolerance.
- Record the renderer version, Python version, operating system and installed fonts with the build metadata. Font changes can alter line wrapping and page count.
Do not claim pixel identity across renderers. Decide which properties matter—text presence, page count, margins, key visual regions—and test those properties explicitly.
Organize the implementation in GitHub Projects
Create a project for the conversion effort and use issues for decisions and verifiable work. The project is a planning and visibility layer; the Python code and its tests remain in the repository.
Suggested issue sequence
- Select the renderer. Record whether the input needs browser JavaScript, which CSS features are required and what the representative fixture contains.
- Create the minimal HTML fixture. Include a known title, a page break and one local asset.
- Implement conversion. Add the WeasyPrint or Playwright adapter and a command or function with a clear input and output path.
- Define page and asset handling. Decide paper size, margins, fonts, image policy, URL access and how missing assets fail.
- Add an output check. Verify file creation and representative content; add a visual review step if layout is critical.
- Document environment setup. Include Python version, native libraries or browser binaries, and the exact verification command.
- Review security. Assess untrusted HTML/CSS, remote requests, file access, resource limits and isolation before accepting user input.
Useful project fields
| Field | Example values | Why it helps |
|---|---|---|
| Status | Backlog, Ready, In progress, Review, Done | Shows flow without reading every issue |
| Renderer | WeasyPrint, Playwright, undecided | Makes the main technical choice visible |
| Risk | Low, Medium, High | Highlights security, asset and compatibility work |
| Validation | Not started, Automated, Visual review | Prevents “code complete” from being mistaken for “output verified” |
Define “done” in each issue
An issue should name its input fixture, expected PDF properties, test command and documentation change. Link pull requests to the issue and move the item only when those checks pass. This keeps renderer experiments and production-ready work separate.
Troubleshoot common failures
Import or shared-library errors with WeasyPrint
Cause: a missing or incompatible native dependency. Fix: follow the current operating-system installation guide, activate the intended virtual environment and run weasyprint --info. Do not solve a system-library error by randomly pinning Python packages.
Images, CSS or fonts are missing
Cause: relative URLs have no usable base, the asset is unreachable, or the font is not installed. Fix: use an absolute base_url for string input, verify paths inside the runner, package required fonts and inspect the generated PDF rather than assuming a warning means the page is correct.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Playwright reports that a browser is missing
Cause: the Python package is installed but browser binaries are not. Fix: run playwright install chromium in the same environment used by the converter and repeat the launch test.
The PDF is blank or captures an unfinished page
Cause: conversion occurred before application rendering completed, or the selected media is wrong. Fix: wait for a meaningful selector or application-ready signal; for Playwright, remember that PDF output defaults to print media and explicitly emulate screen media when appropriate.
Layout changes between machines
Cause: different fonts, renderer versions, browser binaries or operating systems. Fix: pin application dependencies, document native requirements, provide fonts where licensing permits and run the representative fixture in the same CI environment used for releases.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Handle untrusted HTML as a security boundary
WeasyPrint’s documentation warns that untrusted HTML or CSS can create security problems. Do not treat arbitrary user input as safe merely because the output is a PDF. Sanitize input according to your application’s policy, restrict network access and file visibility, limit document size and conversion time, and isolate the worker from credentials and sensitive host paths. Apply equivalent controls to browser-based conversion, including sandboxing and a narrow outbound network policy. Log failures without storing secrets embedded in URLs or headers.
Best Value
Performance, reliability and cost decisions
- Reuse a warm worker only after confirming that renderer state, cookies and temporary files cannot leak between jobs.
- Bound concurrency to the memory and CPU available on the runner; browser processes and large image-heavy documents can be expensive.
- Cache deterministic inputs using a content hash, but invalidate the cache when templates, fonts, renderer versions or relevant assets change.
- Separate retryable network failures from deterministic template errors. Retrying malformed HTML rarely helps.
- Measure your own representative documents. The available documentation does not establish a universal speed or fidelity winner between WeasyPrint and Playwright.
Or skip the browser setup
If the HTML is publicly reachable and you need a hosted capture rather than maintaining a rendering worker, ScreenshotNeo provides a website screenshot API and MCP server. It can return PNG, JPEG, WebP or PDF output; use the response-format options in the API documentation for a PDF response.
One GET request is enough to start a capture:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/report -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/report"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/report' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Before the capture, ScreenshotNeo accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the page verdict and billing status with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Can one project support both renderers?
Yes. Keep a shared input and output contract, then implement separate WeasyPrint and Playwright adapters behind it. This lets a fixture decide which renderer is appropriate without duplicating project tracking.
Should generated PDFs be committed to Git?
Usually no for every build. Commit a small reviewed sample only when it documents a contract; publish routine PDFs as build artifacts and regenerate them from versioned templates.
How do I decide whether a visual diff is too large?
Set the threshold from business impact: strict for invoices or regulated forms, looser for prose reports. Have a human review intentional template changes and record the reason beside the approved baseline.
Frequently Asked Questions
Can one project support both renderers?
Yes. Keep a shared input and output contract, then implement separate WeasyPrint and Playwright adapters behind it.
Should generated PDFs be committed to Git?
Usually no for every build; publish routine PDFs as build artifacts and regenerate them from versioned templates.
How do I decide whether a visual diff is too large?
Set the threshold from business impact and review intentional template changes against an approved baseline.
PC 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 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteQuick 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.




