ScreenshotNeo

BlogHow-to

How to Add Headers and Page Numbers to Html2Pdf.app PDFs

Add headers, footers, and page numbers to Html2Pdf.app PDFs using templates, reserved margins, and a working API request.

By the ScreenshotNeo team4 October 20267 min read

To add headers or page numbers to an Html2Pdf.app PDF, pass HTML in headerTemplate and/or footerTemplate. Put <span class="pageNumber"></span> where the current page should appear and <span class="totalPages"></span> where the total should appear. Reserve space with marginTop and marginBottom; otherwise the template may have too little room to show.

For recurring or application-driven PDFs, use the API. For a one-off conversion, the online converter provides an interactive route with header and footer controls. The API accepts HTML or a public URL and returns PDF bytes on a successful synchronous request. See the Html2Pdf.app API documentation for the current parameter reference.

This footer prints the current page and total page count. The placeholders are spans with class names; Html2Pdf.app fills in their values during PDF generation.

<div style="font-size: 12px; text-align: center; width: 100%;">
  Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</div>

Use the same markup in headerTemplate if numbering belongs at the top. Templates can also use the documented date, title, and url classes for document values.

The following JSON is a minimal example request body. The margin values are illustrative starting points in pixels, not universal settings; increase them if your template is taller.

{
  "html": "<h1>Example report</h1><p>Report content goes here.</p>",
  "headerTemplate": "<div style=\"font-size: 12px; width: 100%; text-align: center;\">Monthly report</div>",
  "footerTemplate": "<div style=\"font-size: 10px; width: 100%; text-align: center;\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>",
  "marginTop": 40,
  "marginBottom": 40
}

Send it as JSON to POST https://api.html2pdf.app/v1/generate and authenticate with the X-API-Key header. Keep that key in a trusted backend or environment variable. Do not place it in browser JavaScript or public source code.

3. Make the API request

cURL

curl --fail-with-body --silent --show-error \
  -X POST "https://api.html2pdf.app/v1/generate" \
  -H "X-API-Key: $HTML2PDF_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @request.json \
  --output report.pdf

Save the JSON example above as request.json. The output file is PDF data, so write the response to a binary file rather than treating it as JSON or text.

Python

import os
import requests

payload = {
    "html": "<h1>Example report</h1><p>Report content goes here.</p>",
    "headerTemplate": '<div style="font-size:12px;width:100%;text-align:center;">Monthly report</div>',
    "footerTemplate": '<div style="font-size:10px;width:100%;text-align:center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
    "marginTop": 40,
    "marginBottom": 40,
}

response = requests.post(
    "https://api.html2pdf.app/v1/generate",
    headers={
        "X-API-Key": os.environ["HTML2PDF_API_KEY"],
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=90,
)
response.raise_for_status()

with open("report.pdf", "wb") as pdf_file:
    pdf_file.write(response.content)

Node.js

import { writeFile } from 'node:fs/promises';

const payload = {
  html: '<h1>Example report</h1><p>Report content goes here.</p>',
  headerTemplate: '<div style="font-size:12px;width:100%;text-align:center;">Monthly report</div>',
  footerTemplate: '<div style="font-size:10px;width:100%;text-align:center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
  marginTop: 40,
  marginBottom: 40,
};

const response = await fetch('https://api.html2pdf.app/v1/generate', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.HTML2PDF_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  const detail = await response.text();
  throw new Error(`PDF generation failed (${response.status}): ${detail}`);
}

const pdf = Buffer.from(await response.arrayBuffer());
await writeFile('report.pdf', pdf);

4. Style templates and choose a workflow

Header and footer templates do not inherit CSS from the source page. Include the styles they need inline or in the template markup. External resources cannot load from a template; if it needs an image, embed it as a base64 data URL. Keep the template self-contained and compact.

Workflow Use it when Notes
Online converter You are converting a document interactively or trying the controls for a one-off PDF. The converter offers header and footer controls and does not require an API key for the interactive demo.
API Your application or backend generates PDFs repeatedly. Authenticate server-side, send options as JSON, check the status, and save successful response bytes as a PDF.

For the online route, use the Html2Pdf.app converter and configure its header or footer controls. The API is the better fit when those settings need to be part of a repeatable generation flow.

5. Check layout and troubleshoot

Symptom Likely cause Fix
Header or footer is missing or clipped The corresponding top or bottom margin does not leave enough room. Increase marginTop for a header or marginBottom for a footer until the full template fits.
Page count placeholders are blank The expected class name or span markup is absent or misspelled. Use <span class="pageNumber"></span> and <span class="totalPages"></span> exactly.
Template looks unstyled Template CSS is separate from source-page CSS. Put necessary styles in the template itself rather than relying on the page stylesheet.
Template image does not appear External resources cannot load inside header/footer templates. Embed the image as a base64 data URL.
PDF is blank or page styles are missing The source URL may not be publicly reachable, or its CSS, fonts, images, or other resources may be inaccessible to the rendering service. Use HTML directly or make required resources reachable by the renderer, then inspect the source and response status.
Request fails with an authentication error The API key is missing, invalid, or sent under the wrong header. Send the key in X-API-Key from a trusted backend and confirm the environment variable is set.
Saved file is not a valid PDF The error response may have been saved as though it were successful PDF bytes. Check the HTTP status before writing the file; inspect the error body for unsuccessful responses.

6. Reliability, performance, and cost

Keep the input document and its dependencies available to the renderer for the duration of generation. When a public URL relies on remote stylesheets, fonts, or images, those dependencies add possible failure points; inline critical styles or use HTML input when that suits your workflow. Reuse a stable template and adjust its margins based on the actual rendered header and footer height.

For reliable application integration, keep credentials server-side, set a request timeout appropriate to your job, check non-success HTTP statuses, and retain the response as bytes. If PDF generation is user-facing, return a clear error when generation fails rather than serving an empty or partial file.

The research sources do not establish Html2Pdf.app pricing or generation-time benchmarks, so this guide makes no cost or speed estimates. Check the provider’s current plan terms for your expected volume. The interactive converter is described as a free demo; automated API use requires an API key.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. It returns screenshots or PDFs from one request and provides API documentation. For a PDF capture of a page, request PDF output using its documented options; a basic image request looks like this:

cURL

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}`);

ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. These are website captures, with PDF output available through the API; use Html2Pdf.app when you specifically need its HTML-to-PDF template workflow.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Can I show both the current page and total pages?

Yes. Put the pageNumber and totalPages spans in the same header or footer template.

Can the header use my source page’s stylesheet?

No. Template styles are separate. Include the needed styling in the template markup.

Should I use the converter or API?

Use the converter for an interactive one-off. Use the authenticated API when generation belongs in an application or repeatable backend workflow.