October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
CSS

How to Set Different First-Page Margins With Python pdfkit

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

Use CSS paged-media rules in the HTML you give to pdfkit: define the normal page margin in @page, then override the first page with @page :first.

@page {
  margin: 20mm;
}

@page :first {
  margin-top: 35mm;
}

Python pdfkit passes that HTML to the wkhtmltopdf executable. The CSS rule is defined by CSS 2.2, but support depends on the exact wkhtmltopdf build installed on your machine, so render a two-page test and inspect the output before relying on it in production.

What the two margin layers control

There are two separate places to set margins:

Layer Typical setting Scope Best use
Renderer options margin-top, margin-right, margin-bottom, margin-left Every page in the rendered document A common baseline supplied from Python to wkhtmltopdf
Paged CSS @page and @page :first General page box and first-page override A first-page-only difference expressed in the stylesheet

pdfkit is a Python wrapper, not the PDF layout engine. Its documented options map to wkhtmltopdf command-line switches; CSS is interpreted later by wkhtmltopdf’s rendering engine. The wkhtmltopdf usage documentation lists page-wide margin switches but does not document a first-page-specific command-line switch: wkhtmltopdf usage options.

CSS 2.2 defines :first as a page selector and states that declarations in the more specific first-page rule override the general @page rule: W3C paged media specification.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Install and verify the toolchain

Install Python pdfkit

python -m pip install pdfkit

You also need a wkhtmltopdf executable. Install the package appropriate for your operating system, then verify that it is on your PATH:

wkhtmltopdf --version

Record this version with your deployment configuration. wkhtmltopdf describes its renderer as an older WebKit/Qt stack, and its status page explains the project’s maintenance state: wkhtmltopdf status. A distribution package, a manually downloaded binary and a container image can therefore behave differently.

Point pdfkit at a non-standard executable

If the command is not on PATH, pass its absolute path:

import pdfkit

config = pdfkit.configuration(
    wkhtmltopdf="/absolute/path/to/wkhtmltopdf"
)
pdfkit.from_string("<p>test</p>", "test.pdf", configuration=config)

Use a real executable path for your platform. On Windows, for example, this is commonly a path under Program Files; on Linux containers it is often /usr/bin/wkhtmltopdf.

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

A complete two-page example

The following example deliberately creates enough content for two pages. The first page gets a 35 mm top margin; subsequent pages use 20 mm on all sides.

HTML and CSS

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style>
    @page {
      size: A4;
      margin: 20mm;
    }

    @page :first {
      margin-top: 35mm;
    }

    * { box-sizing: border-box; }
    html, body { margin: 0; padding: 0; }
    body {
      font-family: Arial, sans-serif;
      font-size: 11pt;
      line-height: 1.45;
    }
    h1 { margin: 0 0 8mm; }
    p { margin: 0 0 5mm; }
    .page-break { page-break-before: always; }
  </style>
</head>
<body>
  <h1>Report title</h1>
  <p>This content starts lower because the first page has a 35 mm top margin.</p>
  <p>Add enough paragraphs, rows or sections to force a second page.</p>
  <div class="page-break"></div>
  <h2>Second-page section</h2>
  <p>This page returns to the 20 mm top margin.</p>
</body>
</html>

Python with pdfkit

from pathlib import Path
import pdfkit

html = Path("report.html").read_text(encoding="utf-8")

options = {
    "page-size": "A4",
    "encoding": "UTF-8",
    "print-media-type": None,
    "quiet": None,
}

# Leave the margins in CSS so @page :first owns the distinction.
pdfkit.from_string(html, "report.pdf", options=options)
print("Wrote report.pdf")

The None values above are pdfkit’s way to emit boolean wkhtmltopdf switches. You can omit print-media-type if your stylesheet does not use media queries. If you set margin-top or the other margin options in Python, those values are page-wide renderer settings; they are useful for a common baseline but may affect how a particular binary applies CSS page margins. Keep the test document and verify the result after changing either layer.

Setting a common baseline from Python

Sometimes deployment code owns the paper settings while the template owns the first-page adjustment. You can pass the common values through pdfkit:

options = {
    "page-size": "A4",
    "margin-top": "20mm",
    "margin-right": "20mm",
    "margin-bottom": "20mm",
    "margin-left": "20mm",
    "encoding": "UTF-8",
}
pdfkit.from_string(html, "report.pdf", options=options)

Then retain the @page :first rule in the stylesheet and test the installed wkhtmltopdf version. If the first-page difference disappears, remove the conflicting per-side command-line margin and let CSS provide both the baseline and the override, or treat the renderer as lacking reliable support for this rule.

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

Margins, padding and headers are not the same thing

Page-box margin

@page controls the printable page box. It changes where the document’s page area begins, including the first-page override.

Body and element spacing

Rules such as body { margin: 8px; }, heading margins, container padding and table spacing are ordinary content-box styles. They add whitespace inside the page area and can make a page-margin change appear too small or too large. Reset them while diagnosing:

html, body {
  margin: 0;
  padding: 0;
}

Headers and footers

wkhtmltopdf header and footer options reserve their own space. A header can make the first page’s content look lower even when the page margin is identical. Test with headers and footers disabled, establish the page-margin behavior, then add them back and adjust their spacing independently.

Verify first-page support on your actual binary

  1. Save the sample HTML as margin-test.html.
  2. Confirm the file necessarily produces at least two pages; use a forced page break or substantial text.
  3. Run wkhtmltopdf --version and save the output with your build artifacts.
  4. Generate the PDF through the same Python code and executable used in deployment.
  5. Open the PDF and compare the distance from the physical top edge to the first-page heading and to the second-page heading.
  6. Repeat on every operating-system image or container that will render documents.

This is a regression check you can keep in CI as a visual or coordinate comparison. It is especially important because the wkhtmltopdf issue tracker contains a report of a first-page top-margin discrepancy: issue #3820. That report is evidence of a problem in a particular implementation, not a universal compatibility result.

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.

Troubleshooting

The first page looks identical to later pages

  • Confirm the document has two pages; a one-page render cannot show a difference.
  • Reset body, headings and wrapper padding to zero while testing.
  • Check that the selector is exactly @page :first, with a space before :first.
  • Remove Python margin-* options temporarily so you can determine whether command-line settings are taking precedence.
  • Test the same HTML with the exact wkhtmltopdf binary from production. Standards support does not guarantee implementation support in an older build.

There is unexpected whitespace only around a heading

Inspect the heading’s own margin-top, the first child’s collapsing margin and any wrapper padding. These are content styles, not page-box margins. Set explicit values such as h1 { margin: 0 0 8mm; } while isolating the issue.

The script raises “No wkhtmltopdf executable found”

Install wkhtmltopdf, add it to PATH, or pass an absolute path through pdfkit.configuration(). Run that path directly in a shell to catch permissions or missing shared-library errors.

The PDF is blank or conversion exits with an error

  • Run without quiet so wkhtmltopdf’s diagnostic output is visible.
  • Use a local HTML file first to separate renderer problems from network, JavaScript or asset-loading problems.
  • Check that referenced fonts, images and stylesheets are readable by the rendering process.
  • For local files, enable the wkhtmltopdf local-file option only when required by your document and deployment policy.

The first page is correct but later content shifts unexpectedly

Look for a large first-page-only element, a forced page break, oversized header, or content that cannot fit in the remaining page box. A margin changes available content height; it can legitimately move a block to the next page.

Choosing values and keeping renders stable

Use physical units

Use mm, cm or in for print margins. They communicate the intended paper geometry more clearly than pixels and avoid tying the template to a screen density.

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

Keep the distinction in one place

Put the normal and first-page values together in the same @page block. Keep Python options for paper size, encoding, orientation and other deployment-level choices unless you have verified how your wkhtmltopdf version combines them with CSS.

Expect layout cost from a larger first margin

A 35 mm first-page top margin leaves less vertical room than a 20 mm margin. Long headings, tables and images may move to page two. If page count matters, test with the largest realistic title, logo and introductory content rather than a minimal placeholder.

Cache and compare deterministic inputs

For reliable regression checks, pin the wkhtmltopdf binary, fonts, CSS and input data. A changed font or image dimension can look like a margin regression even when the page rule is unchanged.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean visual capture of a rendered web page rather than a print-oriented PDF, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; failed loads, bot checks or blank pages are not billed, and each response reports the page verdict and billing status in headers.

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

One GET request is enough:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for options such as PNG, JPEG or WebP output, full-page capture with lazy images loaded, CSS-selector element capture, device and retina settings, custom CSS or JavaScript, waiting for a selector or network idle, request blocking, cookies and headers, timezone and geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks and bulk capture of up to 100 URLs per call.

Python

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)

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}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo’s MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots, with every feature available on every plan. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I convert a URL instead of an HTML string?

Yes. Use pdfkit’s from_url() method and keep the same @page rules in the page’s stylesheet. Ensure the renderer can reach the stylesheet and any fonts or images before judging the margin result.

Do I need a separate CSS file for the first-page rule?

No. The rule can be inline in the document passed to pdfkit or loaded from a stylesheet. Inline CSS is often simplest for a self-contained regression fixture.

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

Is a larger first-page margin suitable for every paper size?

Not automatically. Recheck the available content height when changing between A4, Letter or custom sizes; the same millimetre value can push different content onto a new page.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.