Guide
Add page numbers to a PDF
Pass header_html or footer_html in your render options to stamp a header or footer on every page of the generated PDF. The renderer substitutes special class names with live values: current page, total pages, date, title, and URL.
The minimal example
Add a centered page number to every page. The .pageNumber span is replaced by the renderer with the current page number on each page.
const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.PDFPIPE_KEY}`,
},
body: JSON.stringify({
html: "<h1>My Report</h1><p>Content here...</p>",
options: {
format: "A4",
footer_html: `
<div style="
font-family: sans-serif;
font-size: 10px;
color: #888;
text-align: center;
padding: 0 1cm;
width: 100%;
">
Page <span class="pageNumber"></span>
</div>
`,
},
}),
});Available substitution classes
Use these class names anywhere inside your header or footer HTML. The renderer replaces the content of each element with the live value for that page.
| Class | Replaced with |
|---|---|
| .pageNumber | Current page number (1-based) |
| .totalPages | Total number of pages in the document |
| .date | Current date at render time |
| .title | The <title> element of the rendered HTML |
| .url | The URL of the rendered page (for URL renders) |
Header and footer together
Use both at once. A common pattern for reports: document title in the header, page counter in the footer.
const HEADER = `
<div style="
font-family: Georgia, serif;
font-size: 9px;
color: #555;
display: flex;
justify-content: space-between;
padding: 0 1cm;
width: 100%;
border-bottom: 1px solid #ddd;
">
<span>Acme Corp: Q2 2026 Report</span>
<span class="date"></span>
</div>
`;
const FOOTER = `
<div style="
font-family: Georgia, serif;
font-size: 9px;
color: #999;
text-align: right;
padding: 0 1cm;
width: 100%;
">
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</div>
`;
const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.PDFPIPE_KEY}`,
},
body: JSON.stringify({
html: reportHtml,
options: {
format: "A4",
margin: "2cm", // give headers/footers room
header_html: HEADER,
footer_html: FOOTER,
},
}),
});Margin tip
The renderer automatically widens the top and bottom margins from 1cm to 2cm when you use the default 1cm margin, so the header and footer do not overlap your content. If you set a custom margin, set it large enough for your header or footer height. A 40 to 50 px header comfortably fits inside 2cm of space.
Python example
import os, requests
FOOTER = """
<div style="font-family:sans-serif;font-size:10px;color:#999;
text-align:right;padding:0 1cm;width:100%">
Page <span class="pageNumber"></span> / <span class="totalPages"></span>
</div>
"""
resp = requests.post(
"https://api.pdfpipe.xyz/v1/pdf",
headers={"Authorization": f"Bearer {os.environ['PDFPIPE_KEY']}"},
json={
"html": "<h1>Invoice #4012</h1><p>...</p>",
"options": {
"format": "A4",
"footer_html": FOOTER,
},
},
)
resp.raise_for_status()
with open("invoice.pdf", "wb") as f:
f.write(resp.content)Styling notes
Headers and footers render in a separate browser frame from the main document. A few things to keep in mind:
- Inline styles work reliably. External stylesheets and web fonts do not load in the header/footer frame.
- Set
width: 100%on the root element to span the full page width. - Use
padding: 0 1cmto match the horizontal margin of the main document body. - Font size of 9 to 11px is typical. The header/footer area is small; large text will overflow.
- Background colors are printed in the header/footer frame without needing
print_background: true.
Try the header/footer options in the playground (expand “Options” to reveal the header/footer fields), or read the full API reference.
See pricing →