How to Generate PDFs from HTML with Python pdfkit
Use Python-PDFKit and wkhtmltopdf to turn a URL, HTML file, or HTML string into a PDF, set page options, and diagnose common setup problems.
To generate a PDF from HTML with Python-PDFKit, install both the pdfkit Python package and the separate wkhtmltopdf executable. Then call pdfkit.from_url(), pdfkit.from_file(), or pdfkit.from_string() depending on your input. Python-PDFKit is a wrapper; it does not render the PDF itself.
1. Install Python-PDFKit and wkhtmltopdf
Install the Python package in your environment:
python -m pip install pdfkit
Install wkhtmltopdf separately using the package or installer for your operating system. Follow the official wkhtmltopdf downloads page for available builds. Some distribution packages may have reduced functionality compared with builds that include the project’s Qt patches, so verify the installed binary and the options it supports.
Confirm that the executable is available to your process:
wkhtmltopdf --version
If that command is not found, install the executable or make its directory available on PATH. In containers and servers, ensure the binary is installed in the runtime environment, not only on your development machine.
2. Generate a PDF from a URL, file, or HTML string
Choose the function that matches where the HTML comes from. These examples write a PDF to disk:
import pdfkit
# Render a web page.
pdfkit.from_url("https://example.com", "page.pdf")
# Render an HTML file.
pdfkit.from_file("report.html", "report.pdf")
# Render an HTML string.
html = "<!doctype html><html><body><h1>Hello</h1></body></html>"
pdfkit.from_string(html, "hello.pdf")
The source can be a URL, a path to a file, or an HTML string. If you omit the output path, the function returns PDF bytes, which you can pass to another library or write to a stream:
import pdfkit
pdf_bytes = pdfkit.from_string("<h1>Hello</h1>", False)
with open("hello.pdf", "wb") as pdf_file:
pdf_file.write(pdf_bytes)
Use a writable output location and make sure the process has permission to create or replace the file. For URL input, the conversion process must also be able to reach the site and its resources.
3. Configure wkhtmltopdf and page layout
Python-PDFKit passes an options dictionary through to wkhtmltopdf. Option names omit the leading --. For example:
import pdfkit
options = {
"page-size": "A4",
"orientation": "Portrait",
"margin-top": "12mm",
"margin-right": "12mm",
"margin-bottom": "12mm",
"margin-left": "12mm",
"encoding": "UTF-8",
}
pdfkit.from_file("report.html", "report.pdf", options=options)
Common layout controls include paper size, custom page dimensions, orientation, margins, and print-media behavior. wkhtmltopdf also documents JavaScript controls and local-file access controls. See the wkhtmltopdf usage documentation for supported command-line options. Availability can vary by installed build; if a setting appears ignored, verify it with that binary’s help output and by running the equivalent command directly.
Use a nonstandard executable path
PDFKit tries to discover wkhtmltopdf automatically. If it is installed outside the normal search path, give PDFKit the executable location explicitly:
import pdfkit
config = pdfkit.configuration(wkhtmltopdf="/path/to/wkhtmltopdf")
pdfkit.from_string("<h1>Hello</h1>", "hello.pdf", configuration=config)
Replace the example path with the actual path on the machine running the script. The project documents automatic discovery through which on Unix-like systems and where on Windows.
Render pages that depend on JavaScript or local assets
If a page builds content with JavaScript, check the wkhtmltopdf JavaScript options and give the page enough time to finish rendering. If images, stylesheets, or fonts are local files, check the binary’s local-file access behavior and allow only the files the conversion needs. A URL render and a local HTML file can resolve relative assets differently, so use paths or URLs that are valid from the conversion process’s point of view.
4. Diagnose conversion failures
Enable verbose output when a conversion fails. You can also create a PDFKit object and inspect the command it generates, then run that command directly to isolate whether the issue is in the Python wrapper or the converter:
import pdfkit
pdf = pdfkit.PDFKit(
"https://example.com",
"url",
options={"page-size": "A4"},
)
print(pdf.command())
pdf.to_pdf("debug.pdf", verbose=True)
Use the generated command as a diagnostic aid; it can expose URLs and option values supplied to the conversion. Avoid logging secrets in URLs or arguments.
Common errors and fixes
| Symptom | Likely cause | What to check |
|---|---|---|
No wkhtmltopdf executable found |
The executable is missing or not discoverable by the Python process. | Install it, check PATH in the actual runtime, or pass its full path to pdfkit.configuration(). |
| The command fails or PDF output is missing | The converter returned an error, could not fetch the page, or could not write the destination. | Use verbose=True, inspect the generated command, check network access and destination permissions, and run the command directly. |
| A layout or JavaScript option seems ignored | The installed build may not support that option or feature. | Check the installed binary’s documentation and test the equivalent option on the command line. |
| Images or styles are missing | Resource URLs may be inaccessible or local-file access may be restricted. | Check that resource paths resolve from the converter, and review the installed version’s local-file access controls. |
| Text or characters render incorrectly | Encoding or font availability may differ in the runtime environment. | Set an appropriate encoding such as UTF-8, check the source document’s encoding, and ensure needed fonts are installed. |
5. Security, maintenance, and operational notes
Do not pass untrusted HTML to wkhtmltopdf
The wkhtmltopdf project warns against converting untrusted HTML and JavaScript without sanitizing it, because doing so can put the server at risk of complete takeover. Treat user-controlled markup and scripts as security-sensitive input. Sanitize it and isolate conversion work appropriately for your application. Read the warning on the wkhtmltopdf downloads page.
Account for the project’s deprecated status
The Python-PDFKit README marks the library deprecated to match the status of the wkhtmltopdf project. That matters when choosing a dependency for a new system: assess whether its maintenance status and rendering behavior fit your support requirements. The sources used here do not establish a specific replacement, so evaluate alternatives against your own HTML, deployment, and security needs.
Plan for runtime and reliability
The conversion runs an external executable, so production reliability depends on both the Python package and the installed binary. Pin and document the runtime environment, verify the executable during deployment, set appropriate process limits, and handle conversion errors rather than assuming every page will render. Test representative pages with the same binary and fonts used in production. The supplied project documentation provides no performance benchmarks or cost figures, so measure conversion time and resource use with your own documents and workload.
6. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. For a web page, one GET request can return an image or PDF without installing wkhtmltopdf. See the ScreenshotNeo API documentation for request options.
curl -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,
)
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}`);
For a PDF response, request PDF output using the documented API option. ScreenshotNeo removes cookie banners, popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 screenshots. This is suited to capturing web pages; PDFKit remains the workflow above for converting arbitrary HTML strings or local files.
Start with 1,000 free screenshots a month, no card required.
7. Frequently asked questions
Does installing pdfkit install wkhtmltopdf too?
No. Install the Python package and the separate executable.
Can I use PDFKit with an HTML string without saving an input file?
Yes. Pass the string to from_string(); provide an output path or request returned PDF bytes.
Can this workflow create a PDF from a local HTML file?
Yes. Use from_file() and check that the converter can access any local assets the page references.
Is Python-PDFKit a good default for a new project?
Its README marks it deprecated, so review that lifecycle status before adopting it for a new system.


