PDF Generation

Generate PDFs with configurable page size, margins, orientation, and background printing. nokap leverages Chrome’s built-in print-to-PDF functionality through the DevTools Protocol, giving you access to the same rendering engine used for on-screen display. This page walks through all available PDF options including standard paper sizes, custom dimensions, margin control, and header/footer configuration.

Basic PDF Capture

nokap determines the output format from the file extension. Any webshot() or from_html() call with a .pdf output extension generates a PDF instead of a raster screenshot (no separate function or mode switch is required):

import nokap

nokap.webshot("https://example.com", "page.pdf")

Page Size

For full-page PDFs, the page_size parameter controls the paper dimensions. This affects how content is paginated and how much fits on each page:

nokap.webshot("https://example.com", "a4.pdf", page_size="a4")
nokap.webshot("https://example.com", "letter.pdf", page_size="letter")

Available page sizes:

Size Dimensions (inches)
letter 8.5 × 11
legal 8.5 × 14
tabloid 11 × 17
ledger 17 × 11
a0 33.1 × 46.8
a1 23.4 × 33.1
a2 16.5 × 23.4
a3 11.7 × 16.5
a4 8.27 × 11.7
a5 5.83 × 8.27
a6 4.13 × 5.83

Margins

Set page margins in inches. A single value applies to all sides:

# 1-inch margins on all sides
nokap.webshot("https://example.com", "page.pdf", margins=1.0)

# No margins
nokap.webshot("https://example.com", "page.pdf", margins=0)

For asymmetric margins, pass a 4-tuple of (top, right, bottom, left):

nokap.webshot(
    "https://example.com",
    "page.pdf",
    margins=(1.0, 0.75, 1.0, 0.75),  # top, right, bottom, left
)

The default margin is 0.5 inches on all sides.

Orientation

By default, PDFs render in portrait orientation. Use landscape=True to rotate the page, which is useful for wide content like data tables or charts that benefit from extra horizontal space:

nokap.webshot("https://example.com", "wide.pdf", landscape=True)

A Note on Scale

Unlike raster screenshots where zoom controls pixel density, PDFs are a vector format: text and graphics are stored as scalable geometry, not pixels. This means PDFs always render at the highest possible resolution regardless of any scale setting.

Note

The zoom parameter is ignored for PDF output. Use zoom only for raster screenshots (PNG, JPEG, WebP) where it controls output pixel density and sharpness on HiDPI displays.

Element-Bounded PDF

One of nokap’s most powerful features is the ability to produce a PDF that’s sized exactly to a specific element rather than a standard paper size. When you combine a .pdf output with a selector, nokap produces a tightly-bounded PDF with the paper dimensions matched to the element’s bounding box. The text remains fully selectable and searchable (unlike a raster screenshot embedded in a PDF).

This is the feature to reach for when you need to place a table or chart into a presentation (Keynote, PowerPoint, Google Slides) at vector quality, or when you want a compact PDF that contains only the content you care about.

# Capture just the table as a tight-fit PDF
nokap.webshot("report.html", "table.pdf", selector="table", expand=10)

Under the hood, the element-bounded PDF works by:

  1. Measuring the element’s bounding box in CSS pixels
  2. Setting the PDF paper size to exactly match those dimensions (converted to inches)
  3. Injecting print-specific CSS to isolate the element and hide surrounding content
  4. Rendering via Chrome’s Page.printToPDF with zero page margins

The result is a single-page PDF where the page boundary coincides with the element boundary (plus any expand padding you specify).

With from_html()

For packages that generate HTML programmatically (like Great Tables, Plotly, or custom report builders) from_html() is the natural entry point. Pass the HTML string and a selector to extract just the relevant element as a vector PDF:

from great_tables import GT, exibble

html = GT(exibble).as_raw_html(make_page=True, all_important=True)

# Tight PDF of just the table (useful for slides)
nokap.from_html(html, "table.pdf", selector="table", expand=5)

Expand / Padding

The expand parameter adds even whitespace around the element in the PDF. This is purely a visual affordance and it gives the content some breathing room so it doesn’t feel jammed against the edges when placed into a slide or document:

# No padding: PDF edges touch the table
nokap.from_html(html, "tight.pdf", selector="table")

# 20px breathing room on all sides
nokap.from_html(html, "padded.pdf", selector="table", expand=20)

# Asymmetric padding
nokap.from_html(html, "asym.pdf", selector="table", expand=(10, 20, 10, 20))

Backgrounds

Element-bounded PDFs include CSS backgrounds by default. This is intentional: when you’re exporting a styled table or chart, the background colors, borders, and shading are typically essential to the visual design. Full-page PDFs follow Chrome’s printing convention and omit backgrounds unless you explicitly set print_background=True.

Wide Tables

A common challenge with table-to-PDF export is that wide tables get clipped when they exceed the viewport width. nokap handles this automatically: it detects when an element’s natural width is being constrained by the viewport, temporarily widens the viewport to let the content expand, then sizes the PDF paper to fit the full element. No manual vwidth adjustment is needed (even very wide tables with dozens of columns render completely).

import pandas as pd
from great_tables import GT

# A 20-column table that's wider than the default 992px viewport
df = pd.DataFrame({f"col_{i}": [f"val_{i}"] for i in range(20)})
html = GT(df).as_raw_html(make_page=True, all_important=True)

# Automatically expands to fit all columns
nokap.from_html(html, "wide_table.pdf", selector="table", expand=5)

Full-Page PDF vs Element-Bounded PDF

To summarize the two PDF modes and when to reach for each:

Full-Page PDF Element-Bounded PDF
Trigger .pdf output, no selector .pdf output + selector
Paper size Standard (letter, A4, etc.) Sized to element
Content Entire page Just the selected element
Backgrounds Off by default On by default
Use case Print a document Export a table/chart for slides

Both modes produce true vector PDFs with selectable text. The choice comes down to whether you want a traditional paginated document or a compact, element-sized artifact for embedding elsewhere.

PDF from HTML Strings

Just as with screenshots, you can generate a full-page PDF directly from an HTML string using from_html(). This is convenient for generating documents from templates or programmatic HTML without writing to a temporary file yourself:

html = """
<html>
<body>
  <h1>Invoice #1234</h1>
  <table>
    <tr><td>Widget</td><td>$10.00</td></tr>
    <tr><td>Gadget</td><td>$25.00</td></tr>
    <tr><th>Total</th><th>$35.00</th></tr>
  </table>
</body>
</html>
"""

nokap.from_html(html, "invoice.pdf", page_size="a4", margins=1.0)

Complete Example

Here’s a full-page PDF capture with all common options specified explicitly, showing how the parameters work together:

nokap.webshot(
    "report.html",
    "report.pdf",
    page_size="a4",
    margins=(1.0, 0.75, 1.0, 0.75),
    landscape=False,
    print_background=True,
)

And an element-bounded PDF workflow for exporting a styled table to a presentation:

from great_tables import GT, exibble

html = GT(exibble).as_raw_html(make_page=True, all_important=True)
nokap.from_html(html, "table_for_slides.pdf", selector="table", expand=10)

Next Steps

This page covered both full-page and element-bounded PDF generation from standard paper sizes and margins to the tightly-fitted, selector-driven PDFs that are ideal for embedding in presentations. Because PDFs are vector format, you get crisp text at any zoom level without worrying about pixel density.

All of the PDF options covered here are also available via the command-line interface, making it easy to integrate nokap into scripts and automation pipelines.