Header and Footer
Last updated March 23, 2026
Headers and footers let you repeat information on every page of your PDF: a company logo, a document title, page numbers, a date, legal text, etc. PDFMonkey offers three ways to add them, each with different trade-offs. Pick the simplest one that meets your needs.
| Approach | Best for | Supports external images/fonts | Page numbers | Skip cover page |
|---|---|---|---|---|
| Settings-based | Flowing content (contracts, reports) | No (inline only) | Yes | No |
| In-content | Fixed-layout pages (certificates, books) | Yes | Via CSS counter | Yes |
| Paged.js | Flowing content needing rich headers | Yes | Yes | Yes |
Settings-Based Header and Footer
The simplest approach. Open your Template’s Settings tab and fill in the header and/or footer fields. The content is rendered on every page, on top of the document content.
Set your margins first
Basic mode
The default fields give you three slots (left, center, right) per header and footer. You can use two special tags:
[page]— current page number[topage]— total number of pages
Advanced mode
Switch to Advanced mode to write custom HTML. You get full control over the layout and can use these HTML equivalents for page numbers:
<span class="pageNumber"></span> <!-- current page number -->
<span class="totalPages"></span> <!-- total number of pages -->
You can also use dynamic data (Liquid syntax) in advanced mode. For accented characters, apply the entities filter:
{{ company.name | entities }}
Limitations
Settings-based headers and footers are rendered by Chromium’s built-in print header/footer mechanism, which comes with hard constraints:
- No external resources — images, CSS, and fonts cannot be loaded over HTTP. Use data URIs for images and inline
<style>tags for CSS. For fonts, see Fonts in Headers and Footers. - No UTF-8 for accented characters — fixed text needs HTML entities (e.g.
éforé). For dynamic data, use theentitiesfilter. - No JavaScript execution — no workaround.
- No way to skip the cover page — no workaround.
- Limited styling control — the CSS tab does not apply inside the header/footer area. Styles must be inlined.
In-Content Header and Footer
For fixed-layout documents where you control each page individually — certificates, children’s books, slide-style reports — you can place the header and footer directly in your HTML content. This approach gives you full access to the CSS tab, external images, web fonts, and JavaScript. No encoding workarounds needed.
A document is “fixed-layout” when each page is a distinct block with a known size, and content does not flow from one page to the next. Every <div class="page"> is self-contained.
Page numbers with CSS counters
Since the HTML content does not know which page it is on, you use a CSS counter to track page numbers. Here is a portrait A4 example:
<div class="page">
<div>Content of Page 1</div>
<div class="page-number"></div>
</div>
<div class="page">
<div>Content of Page 2</div>
<div class="page-number"></div>
</div>
<div class="page">
<div>Content of Page 3</div>
<div class="page-number"></div>
</div>
/* Initialize a counter named "page" at 0 */
/* Remove default spacing so pages are correctly sized */
body {
counter-reset: page;
margin: 0;
padding: 0;
}
/* A portrait A4 page is 793x1120px */
/* Hide overflow to prevent print zoom artifacts */
.page {
height: 1120px;
overflow: hidden;
position: relative;
width: 793px;
}
/* Position the page number at the bottom-right of each page */
.page-number {
bottom: 30px;
position: absolute;
right: 30px;
text-align: right;
}
/* Increment the counter and display it */
.page-number::before {
counter-increment: page;
content: counter(page);
}

CSS counters are more robust than hardcoding numbers in the HTML because they stay accurate when pages are conditionally shown/hidden or generated in a loop.
Limitations
- Only works for fixed-layout documents. If your content flows across pages (like a long contract), you cannot predict where page breaks will fall, so you cannot place a footer at the bottom of each page. Use Paged.js instead.
Paged.js Header and Footer
Paged.js is a JavaScript library that implements the CSS Paged Media specification. It gives you full-featured running headers and footers for flowing content — with full CSS, fonts, images, and JavaScript support.
Paid plan required
How it works
Paged.js uses two CSS concepts:
- Running elements — you define HTML elements and declare them as
running()in CSS. They are removed from the normal flow. - Margin boxes — in an
@pagerule, you place those running elements into page margin areas (@top-center,@bottom-center, etc.).
Step-by-step example
1. Define header and footer elements in your HTML:
<div id="pageHeader">
<div class="header-content">
<img src="https://placekitten.com/60/60" />
<div>Header Text</div>
</div>
</div>
<div id="pageFooter">
<div class="footer-content">
<div>Footer Left</div>
<div>Footer Right</div>
</div>
</div>
<div class="content">Your document content goes here.</div>
<script src="https://cdn.jsdelivr.net/npm/pagedjs@0.3.5/dist/paged.polyfill.js"></script>
2. Declare them as running elements and style them in your CSS tab:
CSS tab only
@page rule below must go in the CSS tab, not in a <style> tag inside the HTML tab. Otherwise it will not work./* Declare as running elements */
#pageHeader {
position: running(pageHeader);
}
#pageFooter {
position: running(pageFooter);
}
/* Style the header and footer content */
.header-content, .footer-content {
align-items: center;
background: #1f2937;
color: #fff;
display: flex;
height: 80px; /* Match this with the @page margin below */
justify-content: space-between;
padding: 0 30px;
}
.content {
text-align: center;
}
3. Place them in the page margins:
@page {
size: A4;
/* Use the same height as the header/footer content */
margin: 80px 0;
/* Place running elements in page margins */
@top-center { content: element(pageHeader); }
@bottom-center { content: element(pageFooter); }
}
The result:

Page size
A3, Letter, etc. or pixel values. See default page sizes in pixels.Names must match
running(pageHeader) must match the name in element(pageHeader). If you used running(superHeader), you would call element(superHeader).Known issue: multi-page table headers
Paged.js can break tables that span multiple pages when they have <thead> elements. If you run into this, see this workaround on GitHub.
Learn more
For page counters, dynamic content in margins, first-page exceptions, and other advanced features, see the Paged.js documentation on Generated Content in Margin Boxes.
Frequently asked questions
- How do I add headers and footers to a PDFMonkey PDF?
- PDFMonkey offers three approaches: settings-based (fill in the header/footer fields in the Settings tab), in-content (place header and footer HTML directly in your template for fixed-layout documents), and Paged.js (a JavaScript library for flowing content with rich headers and footers).
- Can I add page numbers to my PDFMonkey PDF?
- Yes. In settings-based mode use the [page] and [topage] tags. For in-content layouts use CSS counters. With Paged.js, use the built-in page counter support in CSS margin boxes.
- Why are my header and footer images not showing in PDFMonkey?
- Settings-based headers and footers cannot load external resources over HTTP. Use data URIs for images and inline styles for CSS. Alternatively, switch to in-content or Paged.js headers which support external images and fonts.
- How do I skip the header on the first page of my PDF?
- Settings-based headers cannot skip the cover page. Use the Paged.js approach instead — it supports first-page exceptions through CSS @page :first rules and running elements.