Free PDF tool
Add page numbers to a PDF
Add consistent page numbers to reports, contracts and merged documents. Use {page} and {pages} in the format, choose where the numbers appear and whether the cover is counted.
Your PDF stays on your device
- Free, no account needed
- Built on the open-source libraries pdf-lib and PDF.js
How it works
Add page numbers to a PDF in 4 steps
- 1
Add a PDF
Drop the document onto the tool or choose it from your device.
- 2
Set the format
Keep “Page {page} of {pages}” or write your own, such as {page} / {pages}.
- 3
Adjust placement
Choose the position and start number and list pages to skip, such as the cover.
- 4
Number and download
Select Add page numbers and save the numbered PDF.
Questions
Frequently asked questions
Are my files uploaded to a server?
No. The tool runs entirely in your browser: the PDF is read, changed and saved on your device, and its contents are never sent to our servers.
How do I leave the cover page unnumbered?
Enter 1 under pages to skip. Decide whether skipped pages still count: counted, the second page shows 2; not counted, it shows 1.
Do numbers appear correctly on rotated or landscape pages?
Yes. The position is calculated from how the page is displayed, so numbers sit at the visible bottom or top of portrait, landscape and rotated pages.
Can I use password-protected PDFs?
Not in the browser tool. Encrypted PDFs cannot be modified without the password, so the tool reports them instead of producing a broken file. Remove the protection with the software that created it, then try again.
Automate it
Do the same in your application with Dynamic Document API
Number merged or uploaded PDFs server-side. For documents you render from templates, page numbers are usually part of the footer template instead.
POST /v1/pdf-tools/page-numbersPlanned endpointThis endpoint is specified in the public API but not released yet; the request shape may still change.
curl -X POST https://api-eu.dynamicdocumentapi.com/v1/pdf-tools/page-numbers \
-H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"source": {
"render_id": "rnd_01J9ZM1X3F7R8K2C4V6B8N0P2Q",
"file_id": "file_01J9ZM4T6Y8U0I2O4P6A8S0D2F"
},
"format": "Page {page} of {pages}",
"position": "bottom-center",
"font_size": 9,
"start_at": 1,
"skip_pages": "1"
}'const response = await fetch("https://api-eu.dynamicdocumentapi.com/v1/pdf-tools/page-numbers", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DYNAMIC_DOCUMENT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"source": {
"render_id": "rnd_01J9ZM1X3F7R8K2C4V6B8N0P2Q",
"file_id": "file_01J9ZM4T6Y8U0I2O4P6A8S0D2F"
},
"format": "Page {page} of {pages}",
"position": "bottom-center",
"font_size": 9,
"start_at": 1,
"skip_pages": "1"
}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();
console.log(result);import os
import uuid
import requests
response = requests.post(
"https://api-eu.dynamicdocumentapi.com/v1/pdf-tools/page-numbers",
headers={
"Authorization": f"Bearer {os.environ['DYNAMIC_DOCUMENT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"source": {
"render_id": "rnd_01J9ZM1X3F7R8K2C4V6B8N0P2Q",
"file_id": "file_01J9ZM4T6Y8U0I2O4P6A8S0D2F",
},
"format": "Page {page} of {pages}",
"position": "bottom-center",
"font_size": 9,
"start_at": 1,
"skip_pages": "1",
},
timeout=90,
)
response.raise_for_status()
print(response.json())