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 →Set the font in the HTML and CSS that pdfkit sends to wkhtmltopdf. Python’s pdfkit package does not provide a separate body-font API. Define a normal font-family rule (and, when appropriate, an @font-face rule), then pass that stylesheet with css= or through wkhtmltopdf’s user-stylesheet option. Headers and footers are different: wkhtmltopdf has dedicated font-name and font-size options for those regions.
How pdfkit font selection works
pdfkit is a Python wrapper around wkhtmltopdf. Your Python call assembles HTML, CSS and renderer options; wkhtmltopdf performs the actual layout and PDF rendering. Consequently, page content follows CSS, not a special pdfkit font parameter.
- Body, headings, tables and other HTML: use CSS
font-family,font-weightandfont-style. - Header and footer text generated by wkhtmltopdf: use renderer options such as
header-font-nameandfooter-font-size. - Custom font files: declare them with CSS
@font-face, then verify that the renderer can read the files in its production environment.
A font installed in your desktop application is not automatically available to a server, container or CI runner. wkhtmltopdf depends on the runtime’s font configuration, including fontconfig and freetype2.
Set a standard installed font in CSS
Start with a system font so you can confirm that the stylesheet is being loaded:
Recommended Free Tools
#1 Best Overall
/* report.css */
html, body {
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
line-height: 1.45;
}
h1, h2, h3 {
font-family: Georgia, "Times New Roman", serif;
}
Render an HTML file and attach the stylesheet with pdfkit:
import pdfkit
pdfkit.from_file("report.html", "report.pdf", css="report.css")
The same approach works with an HTML string:
import pdfkit
html = """
<!doctype html>
<html>
<head><meta charset="utf-8"></head>
<body><h1>Quarterly report</h1><p>Body text</p></body>
</html>
"""
pdfkit.from_string(html, "report.pdf", css="report.css")
For repeatable output, include an explicit UTF-8 declaration in the HTML and pass an encoding option when non-ASCII characters are present.
Use a custom font with @font-face
The usual implementation is to define the font file in CSS and apply it to the elements that need it:
/* report.css */
@font-face {
font-family: "Report Sans";
src: url("fonts/ReportSans-Regular.ttf") format("truetype");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "Report Sans";
src: url("fonts/ReportSans-Bold.ttf") format("truetype");
font-weight: 700;
font-style: normal;
}
body {
font-family: "Report Sans", sans-serif;
}
strong, b, h1, h2, h3 {
font-weight: 700;
}
This syntax is standard CSS implementation guidance. The official materials do not guarantee that every wkhtmltopdf build supports every font-file format or web-font loading scenario, so validate the exact renderer build and operating system you deploy.
Rank #2
Make relative font paths deterministic
A relative URL such as fonts/ReportSans-Regular.ttf is resolved from the stylesheet or document context used by the renderer. Keep the HTML, CSS and font files in a known directory and test from the same working directory as your service. If you generate temporary files, use absolute paths where practical and ensure the conversion process has read permission.
Choose fallbacks deliberately
Always provide a fallback family. If the custom file cannot be loaded, the PDF will still render, but its metrics, line wrapping and pagination can change. A generic fallback such as sans-serif is safer than allowing an arbitrary platform default.
Attach CSS with css or a user stylesheet
pdfkit documents an external css argument:
import pdfkit
pdfkit.from_file(
"report.html",
"report.pdf",
css="report.css",
)
The wrapper describes this argument as a workaround for a wkhtmltopdf stylesheet issue and recommends trying the renderer’s user-stylesheet option first when it is supported by your installed build:
import pdfkit
options = {
"user-style-sheet": "report.css",
"encoding": "UTF-8",
}
pdfkit.from_file("report.html", "report.pdf", options=options)
pdfkit option names omit wkhtmltopdf’s leading two hyphens. Thus, write user-style-sheet, not --user-style-sheet, in the Python dictionary. If the user stylesheet does not apply in your build, use css= and inspect verbose renderer output.
Free tools Windows power users keep installed
One-click scans. No signup required.
Set header and footer fonts separately
CSS controls HTML content, but wkhtmltopdf-generated headers and footers have their own settings. The renderer exposes --header-font-name, --header-font-size, --footer-font-name and --footer-font-size. Its documented defaults are Arial and size 12 for the corresponding header and footer font settings.
import pdfkit
options = {
"header-left": "Acme Report",
"header-font-name": "Arial",
"header-font-size": 10,
"footer-right": "Page [page] of [topage]",
"footer-font-name": "Arial",
"footer-font-size": 9,
"encoding": "UTF-8",
}
pdfkit.from_file("report.html", "report.pdf", options=options)
These options do not replace the CSS font for the page body. A CSS declaration on body will not necessarily change a renderer-managed header or footer; configure both paths when you need visual consistency.
Use a complete, production-oriented example
The following layout keeps assets together, enables UTF-8 and configures a renderer header and footer:
from pathlib import Path
import pdfkit
base = Path(__file__).parent
html_path = base / "report.html"
css_path = base / "report.css"
pdf_path = base / "out" / "report.pdf"
pdf_path.parent.mkdir(exist_ok=True)
options = {
"encoding": "UTF-8",
"header-left": "Monthly report",
"header-font-name": "Arial",
"header-font-size": 10,
"footer-center": "Page [page] of [topage]",
"footer-font-name": "Arial",
"footer-font-size": 9,
}
pdfkit.from_file(
str(html_path),
str(pdf_path),
css=str(css_path),
options=options,
verbose=True,
)
print(f"Wrote {pdf_path}")
Keep the same wkhtmltopdf executable, operating system image and font packages in development and production. The project identifies 0.12.6 as the stable series, released June 11, 2020; record the actual executable version used by your deployment because distribution builds can differ.
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 errorsDiagnose a font that does not appear
1. Confirm that CSS is loaded
Temporarily set an unmistakable family, such as monospace, and render again. If nothing changes, the problem is stylesheet attachment or path resolution rather than the font file. Verify the css argument or user-style-sheet option and use verbose=True to expose wkhtmltopdf diagnostics.
2. Confirm runtime font availability
Install the font in the same server or container that launches wkhtmltopdf, or reference a file that the process can read. Font availability in a developer’s desktop editor does not prove availability to the renderer. Check the runtime’s fontconfig and freetype2 setup.
3. Check file paths and permissions
Inspect the exact path resolved by the renderer, capitalization and permissions. A CSS URL that works from one working directory can fail when a supervisor, worker queue or container starts the process elsewhere. Prefer a known absolute asset location for diagnostics.
4. Check the actual font metadata
The family name in CSS must match the family declared by the font resource, while font-weight and font-style should match the face you define. If you declare only a regular face and request a heavy weight, the renderer may synthesize or substitute a face.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
5. Separate body, header and footer tests
Render one test with a conspicuous body font and another with a conspicuous header/footer font. If body text changes but the header does not, configure the dedicated header/footer options rather than changing CSS.
6. Compare environments and versions
Record the wkhtmltopdf version, operating system, installed font packages and pdfkit version alongside a failing PDF. The stable 0.12.6 release dates from 2020, so a host’s package may include patches or platform-specific behavior that another host does not.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Reliability and pagination considerations
- Font metrics affect layout: a fallback can widen lines, increase page count or move headings across page breaks.
- Use explicit weights: define regular and bold faces when both are needed instead of relying on synthetic bold.
- Freeze assets for deployments: package the CSS and font files with the application or image, and test after every base-image update.
- Validate the output PDF: inspect glyphs, wrapping, page count and headers in the same viewer and environment used by recipients.
- Keep diagnostics available: enable verbose output during troubleshooting, but route it to controlled logs in production.
Or skip the browser setup
If your real goal is capturing a web page rather than generating a document from HTML, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP or PDF; it is not a replacement for pdfkit’s CSS-to-PDF pipeline, but it avoids maintaining a browser-rendering setup for URL captures.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo documentation for request options. Cookie banners, newsletter popups and chat widgets can be removed before capture; bot checks, blank pages and failed loads are not billed, and response headers report the page verdict and billing status. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up free.
Quick decision guide
| Need | Use |
|---|---|
| Font for normal page content | CSS font-family in the HTML stylesheet |
| Custom typeface file | CSS @font-face, readable by the renderer |
| Attach an external stylesheet | pdfkit css= or supported user-style-sheet |
| Font for wkhtmltopdf header/footer | header-font-* and footer-font-* options |
| Font works locally but not on server | Install/package the font and verify fontconfig, freetype2, paths and permissions |
Frequently Asked Questions
Does pdfkit have a body-font parameter?
No. Set the body font in the HTML/CSS passed to wkhtmltopdf.
Can I use a Google Fonts URL?
The documented material does not guarantee remote web-font behavior across wkhtmltopdf builds. For predictable output, package the font and reference it with a tested local path.
Why does changing CSS not change my footer?
wkhtmltopdf-generated footers use separate footer font-name and footer font-size options; configure those independently.
Which wkhtmltopdf version should I record?
Record the executable and platform actually deployed. The project lists 0.12.6 as the stable series, released June 11, 2020.
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.




