How to Add Page Numbers to a PDF (Free, No Install Required)
Adding page numbers to a PDF before submitting a report, thesis, or contract is a common last-minute task. Most PDF software either costs money or installs an app you'll never use again. Here's how to do it without either.
In the browser (no install)
Open the PDF page numbering tool, upload your PDF, choose position (top or bottom, left/center/right), select the font size and margin, and download the result. Everything runs in your browser — the file never leaves your device.
This handles most real-world PDFs: scanned documents, reports exported from Word, and PDFs generated by any application.
Python: pypdf
pypdf is a pure-Python library that can read and write PDFs without any binary dependencies.
pip install pypdf reportlab
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io
def add_page_numbers(input_path: str, output_path: str, start: int = 1):
reader = PdfReader(input_path)
writer = PdfWriter()
for i, page in enumerate(reader.pages):
page_num = i + start
# Create a PDF overlay with just the page number
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=(
float(page.mediabox.width),
float(page.mediabox.height)
))
# Draw page number centered at bottom
c.setFont('Helvetica', 10)
x = float(page.mediabox.width) / 2
y = 20 # 20 pts from bottom edge
c.drawCentredString(x, y, str(page_num))
c.save()
# Merge overlay onto the page
packet.seek(0)
from pypdf import PdfReader as PR
overlay = PR(packet).pages[0]
page.merge_page(overlay)
writer.add_page(page)
with open(output_path, 'wb') as f:
writer.write(f)
add_page_numbers('report.pdf', 'report-numbered.pdf')
Skip the first page (cover page):
def add_page_numbers_skip_first(input_path: str, output_path: str):
reader = PdfReader(input_path)
writer = PdfWriter()
for i, page in enumerate(reader.pages):
if i == 0:
# Copy first page without a number
writer.add_page(page)
continue
page_num = i # page 2 gets number 1 (i=1), etc.
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=(
float(page.mediabox.width),
float(page.mediabox.height)
))
c.setFont('Helvetica', 10)
c.drawCentredString(float(page.mediabox.width) / 2, 20, str(page_num))
c.save()
packet.seek(0)
overlay = PdfReader(packet).pages[0]
page.merge_page(overlay)
writer.add_page(page)
with open(output_path, 'wb') as f:
writer.write(f)
Format as "Page X of Y":
def add_page_numbers_with_total(input_path: str, output_path: str):
reader = PdfReader(input_path)
total = len(reader.pages)
writer = PdfWriter()
for i, page in enumerate(reader.pages):
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=(
float(page.mediabox.width),
float(page.mediabox.height)
))
c.setFont('Helvetica', 10)
label = f'Page {i + 1} of {total}'
c.drawCentredString(float(page.mediabox.width) / 2, 20, label)
c.save()
packet.seek(0)
overlay = PdfReader(packet).pages[0]
page.merge_page(overlay)
writer.add_page(page)
with open(output_path, 'wb') as f:
writer.write(f)
Python: fpdf2 (creating a new PDF from scratch)
If you're generating a PDF from scratch and want page numbers built in:
from fpdf import FPDF
class NumberedPDF(FPDF):
def footer(self):
self.set_y(-15) # 15mm from bottom
self.set_font('Helvetica', 'I', 8)
self.cell(0, 10, f'Page {self.page_no()}', align='C')
pdf = NumberedPDF()
pdf.set_auto_page_break(auto=True, margin=15)
for i in range(1, 6):
pdf.add_page()
pdf.set_font('Helvetica', size=12)
pdf.cell(0, 10, f'Content on page {i}', ln=True)
pdf.output('document-with-numbers.pdf')
Command line: pdftk
pdftk is a Swiss Army knife for PDF manipulation. It doesn't add page numbers directly, but it can stamp a watermark PDF (containing page numbers) onto each page of another PDF.
# Install
brew install pdftk-java # macOS
sudo apt install pdftk # Ubuntu
# Burst into individual pages
pdftk input.pdf burst output page_%04d.pdf
# Then add numbers per page with another tool and reassemble
pdftk page_*.pdf cat output numbered.pdf
For page numbering specifically, the Python approach above is simpler.
Command line: cpdf (commercial, free for non-commercial)
cpdf is the most capable command-line PDF tool and has native page numbering:
# Add page numbers centered at the bottom
cpdf -add-text "%Page" -bottom 20pt input.pdf -o output.pdf
# Page numbers in "Page X of Y" format
cpdf -add-text "Page %Page of %EndPage" -bottom 20pt -font "Helvetica" -font-size 10 input.pdf -o output.pdf
# Top-right corner
cpdf -add-text "%Page" -topright 20pt input.pdf -o output.pdf
# Start numbering from a specific page (skip first 2 pages)
cpdf -add-text "%Page" -bottom 20pt -firstpage 3 input.pdf -o output.pdf
Position options
Common positions for page numbers and when to use them:
| Position | Format | Typical use |
|---|---|---|
| Bottom center | 1, 2, 3 |
Reports, theses, books |
| Bottom right | 1, 2, 3 |
Business documents |
| Top center | 1, 2, 3 |
Some academic journals |
| Bottom center | Page 1 of 10 |
Legal documents, contracts |
| Alternating left/right | 1 / 1 |
Double-sided print layouts |
For most purposes, bottom center with a simple number is the right choice. It's the convention readers expect.
Key takeaways
- The browser tool handles one-off numbering without any software install.
pypdf+reportlabgives full programmatic control in Python — position, font, format, skipping pages.fpdf2is the easiest path if you're generating a new PDF and want numbers built in from the start.cpdfis the most capable command-line option for automation scripts.- Start numbering from page 2 if your document has a cover page — the cover shouldn't show "1".