Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use a separate HTML file for the header, put the image in that file, and pass it to wkhtmltopdf through pdfkit’s header-html option. Reserve space with margin-top, then use header-spacing to set the gap between the header and the document body.

pdfkit forwards wkhtmltopdf options through its options dictionary. The complete pattern is:

import pdfkit

options = {
    "header-html": "/absolute/path/to/header.html",
    "margin-top": "25mm",
    "header-spacing": "5",
}

pdfkit.from_file("input.html", "output.pdf", options=options)

The paths and measurements above are examples. Your header file, image path, and margin must match the files and layout on the machine running wkhtmltopdf.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How the image header works

wkhtmltopdf treats an HTML header as a separate document. The main page is rendered normally, while the file supplied to --header-html is rendered in the header area of each page. pdfkit uses the same option name without the leading dashes: "header-html".

The top margin is not merely decorative. It is the space reserved for the header. If the header is taller than that space, it can overlap the first line of content or appear clipped. header-spacing adds a gap after the header; excessive spacing can push the header beyond the page area. The wkhtmltopdf library settings describe these page settings, and the usage manual documents HTML headers.

Prerequisites and a reliable file layout

  • Python with the pdfkit package installed.
  • A wkhtmltopdf executable installed separately and available to pdfkit, either on PATH or through pdfkit’s configuration.
  • A main HTML document, a separate header HTML document, and an image readable by the renderer.

A simple project layout keeps path problems visible:

project/
  input.html
  header.html
  assets/
    logo.png
  make_pdf.py

Use absolute paths when diagnosing failures. Relative paths are interpreted by the renderer’s process and can change when a script is launched from another working directory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Step 1: Create the header HTML document

The header is ordinary HTML. Keep its body margin at zero and size the image explicitly so the header height is predictable.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      html, body { margin: 0; padding: 0; }
      .header { width: 100%; text-align: left; }
      .header img { display: block; height: 40px; width: auto; }
    </style>
  </head>
  <body>
    <div class="header">
      <img src="file:///absolute/path/to/logo.png" alt="">
    </div>
  </body>
</html>

Replace the illustrative file:///absolute/path/to/logo.png URL with a path that exists on the conversion host. An empty alt value is appropriate for a purely decorative logo; use descriptive alternative text if the image conveys information.

You can also reference an HTTPS image URL when the wkhtmltopdf build can reach it. A local file is usually easier to make deterministic, but local-file access controls still apply.

Step 2: Reserve room and call pdfkit

Install pdfkit with your normal Python package manager, then create a script such as this:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import os
from pathlib import Path
import pdfkit

root = Path(__file__).resolve().parent
input_html = root / "input.html"
header_html = root / "header.html"
output_pdf = root / "output.pdf"

options = {
    "header-html": str(header_html),
    "margin-top": "25mm",
    "header-spacing": "5",
    "encoding": "UTF-8",
}

pdfkit.from_file(str(input_html), str(output_pdf), options=options)

The from_file call and dictionary-style wkhtmltopdf options are documented in the python-pdfkit README. The encoding setting is optional but helps when the main document contains non-ASCII text.

Choose margin-top from the actual header height, plus any desired breathing room. For a 40-pixel image, 25 mm may be adequate at a typical page scale, but it is not a universal conversion. Render a page, inspect the top edge, and adjust the margin rather than assuming a fixed pixel-to-millimetre ratio.

Equivalent wkhtmltopdf command

Testing the binary directly can distinguish a pdfkit problem from a renderer or path problem:

wkhtmltopdf 
  --header-html /absolute/path/to/header.html 
  --margin-top 25mm 
  --header-spacing 5 
  input.html output.pdf

If this command fails in the same way, fix wkhtmltopdf, its access permissions, or the HTML resources first. If it succeeds while Python fails, inspect pdfkit’s executable configuration and the exact options being passed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Controlling size, alignment and page appearance

Image dimensions

Set one dimension and let the browser preserve the other with width: auto or height: auto. Setting both can distort the logo. CSS units such as millimetres are useful when you need a print-oriented size:

.header img {
  width: 45mm;
  height: auto;
}

Horizontal placement

Use text-align: left, center, or right on the wrapper. For a fixed offset, apply padding to the wrapper, but remember that the available width is affected by the PDF’s left and right margins.

Header and body separation

Increase header-spacing when the first body line is too close to the image. If the header disappears or is cut off, reduce the spacing or increase margin-top; adding spacing without reserving more top margin can move the header outside the printable area.

Page-specific margins

Global page margins can be supplied alongside the header options:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
options = {
    "header-html": "/absolute/path/to/header.html",
    "margin-top": "30mm",
    "margin-right": "15mm",
    "margin-bottom": "15mm",
    "margin-left": "15mm",
    "header-spacing": "4",
}

Keep the header’s internal CSS independent from the main document’s stylesheet. The header is a separate HTML document, so styles from input.html are not a dependable way to format it.

Making local and remote images load

The wkhtmltopdf manual documents image loading as enabled by default and provides the --images and --no-images controls. If an image is missing, check these causes in order:

  1. Open the image path on the conversion machine and verify its filename and case.
  2. Use a correctly formed URL. A local absolute path in HTML should normally be written as a file:/// URL.
  3. Confirm that the installed binary allows local-file access. Builds and security settings can restrict local resources; consult the binary’s own help output for the available local-access switches.
  4. Ensure images have not been disabled with --no-images or an equivalent option.
  5. For an HTTPS image, check DNS, certificates, authentication, and outbound firewall rules from the machine running wkhtmltopdf.

Do not rely on a developer laptop’s current directory, mounted volume, or browser cache. A service account, container, or job runner may see a different filesystem and network.

Common failures and fixes

Symptom Likely cause Fix
The PDF has no header The option was misspelled, the header file cannot be opened, or the installed build does not support the option. Run the equivalent command-line invocation, use an absolute header path, and inspect wkhtmltopdf --version and wkhtmltopdf --help.
The header HTML appears but the image is blank Bad image URL, blocked local file, unreachable remote host, or images disabled. Test the exact URL from the conversion host, verify local-file permissions, and confirm image loading is enabled.
The logo overlaps the first paragraph margin-top is shorter than the rendered header. Increase the top margin; do not try to solve an overlap only by changing body padding.
There is an unexpectedly large gap header-spacing and top margin are both larger than needed. Reduce spacing first, then fine-tune the reserved margin.
Different machines render different results Different wkhtmltopdf builds, patched-Qt support, fonts, file permissions, or network access. Record the binary version, compare help output, package the same build, and make assets local and explicit where possible.
pdfkit raises an executable or configuration error wkhtmltopdf is not on PATH or pdfkit points to the wrong binary. Install or expose the executable and configure pdfkit with the correct binary path before debugging HTML.

Some header and footer capabilities are marked as patched-Qt-only in wkhtmltopdf documentation. If an option is silently ignored, the installed build—not your Python syntax—may be the limiting factor.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Production checklist

  • Use a separate, minimal header document.
  • Use an absolute header path while troubleshooting.
  • Give the image an explicit CSS size and preserve its aspect ratio.
  • Set margin-top to cover the complete rendered header.
  • Use header-spacing only for the additional gap.
  • Verify local-file access, image loading, and remote connectivity on the actual worker machine.
  • Pin or otherwise identify the wkhtmltopdf build used in deployment.
  • Render a multi-page sample to confirm that the header repeats as intended and does not collide with body content.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability and security notes

A small local image avoids a network round trip and removes a common source of intermittent failures. Keep the header HTML lightweight: large images increase memory and PDF generation time, while complicated scripts add another dependency to an otherwise static layout. If the header contains confidential material, protect the image file and avoid placing credentials in a URL. Remote URLs can expose request metadata to the remote host and can fail when a worker has no internet access.

For reproducible output, use the same wkhtmltopdf build, fonts, page size, margins, and asset files across environments. Capture stderr from the conversion process so missing-resource warnings are not lost.

Or skip the browser setup

If your actual goal is a clean image or PDF of a web page rather than a wkhtmltopdf-generated document with a custom header, ScreenshotNeo provides a one-request alternative. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

Use the API documented at https://screenshotneo.com/docs/:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

It also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create an account at https://screenshotneo.com/account/sign-up/.

Frequently asked questions

Frequently Asked Questions

Can I put the image directly in the main HTML file instead of a header file?

Not when you need wkhtmltopdf’s repeating page-header mechanism. Put the image in the separate document supplied through header-html; an image in the body is ordinary page content and will not automatically repeat in the header area.

Why does the header show on some pages but not others?

Check that the PDF is being generated with the header option on the same conversion call and that the header document does not depend on page-specific JavaScript or unavailable resources. Also verify the installed wkhtmltopdf build supports HTML headers.

Should I use a data URI for the logo?

A data URI can avoid filesystem resolution, but it makes the header HTML much larger and is not required by the documented method. A readable local file or reachable URL is simpler to maintain.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.