Adding a watermark to a PDF is one of the most common document-processing tasks in Python. Businesses use watermarks to protect confidential files, publishers use them to mark drafts, and developers use them to stamp documents with a logo, a status label, or a custom message. A watermark can be simple, such as “Confidential” across every page, or more advanced, such as a semi-transparent logo placed in the background of each page.
In this guide, you will learn how to create a Python PDF watermark workflow from scratch. The article covers text watermarks, image watermarks, diagonal placement, transparency, page-by-page processing, and common mistakes to avoid. You will also see practical code examples using popular Python libraries so you can apply watermarking in real projects.
What is a PDF watermark?
A PDF watermark is a visible mark placed on a document page to indicate ownership, status, branding, or restrictions. Watermarks are usually placed behind or over the content of the page and can be:
Text-based, such as “Draft,” “Sample,” or “Confidential”
Image-based, such as a company logo
Repeated on every page or applied to selected pages only
Opaque, semi-transparent, diagonal, or centered
A good watermark should be noticeable without making the document hard to read. In professional document workflows, the watermark often serves as a visual warning or branding element while preserving the original layout.
Why use Python for PDF watermarking?
Python is a strong choice for PDF processing because it is readable, easy to automate, and well supported by libraries. You can use Python to:
Add watermarks to many files in batch
Generate PDFs and watermark them in one workflow
Apply different watermarks based on document type
Build document automation tools for your app or website
Merge, split, rotate, and modify PDFs at the same time
Python also works well in backend systems, so watermarking can be integrated into web applications, APIs, desktop tools, and command-line scripts.
Best Python libraries for PDF watermarking
Several libraries can help you add watermarks to PDFs in Python. The two most useful ones are:
1. pypdf
pypdf is excellent for reading, merging, and modifying PDF files. It is lightweight and ideal for overlaying an existing watermark page onto each page of another PDF.
2. reportlab
reportlab is a PDF generation library. It is very useful when you want to create a watermark page from scratch, especially for text or vector-based designs.
A common approach is to use both together:
Use
reportlabto create the watermarkUse
pypdfto apply it to every page in the source PDF
This is one of the cleanest and most flexible solutions for Python PDF watermarking.
Install the required libraries
Install the packages with pip:
pip install pypdf reportlab
If you plan to work with image watermarks or other PDF manipulations, these two libraries are usually enough for most tasks.
How PDF watermarking works
At a high level, watermarking usually follows this process:
Open the original PDF.
Create a watermark page or overlay.
Merge the watermark with each page of the original PDF.
Save the new PDF.
There are two common strategies:
Overlay strategy
The watermark is drawn on top of the content. This is useful when you want the watermark to be highly visible.
Underlay strategy
The watermark is placed behind the content. This is useful for background branding or subtle page decoration.
Most text watermarks are created as overlays, but semi-transparent designs can work well either way.
Add a text watermark to a PDF in Python
The most common watermark is a text label such as “Confidential,” “Draft,” or “Not For Distribution.” Let’s build a simple and reusable solution.
Example: create a diagonal text watermark
This example uses reportlab to generate a watermark PDF and pypdf to apply it to every page.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.colors import Color
def create_text_watermark(text, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
# Transparent gray color
c.setFillColor(Color(0.5, 0.5, 0.5, alpha=0.2))
c.setFont("Helvetica-Bold", 40)
# Move to center and rotate
c.translate(page_width / 2, page_height / 2)
c.rotate(45)
# Draw centered watermark text
c.drawCentredString(0, 0, text)
c.save()
packet.seek(0)
return PdfReader(packet)
def add_watermark(input_pdf_path, output_pdf_path, watermark_text="CONFIDENTIAL"):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_text_watermark(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as output_file:
writer.write(output_file)
add_watermark("input.pdf", "watermarked.pdf", "CONFIDENTIAL")
How it works
The function create_text_watermark() creates a single-page PDF containing the watermark text. The text is rotated by 45 degrees and made semi-transparent using an alpha value. Then add_watermark() merges that watermark page onto every page of the source PDF.
This approach is powerful because it works with any PDF page size as long as you use the correct dimensions.
Add a centered watermark without rotation
Sometimes a diagonal watermark is too strong. A centered watermark can look cleaner and more professional.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
def create_centered_watermark(text, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.3, 0.3, 0.3, alpha=0.15))
c.setFont("Helvetica-Bold", 32)
x = page_width / 2
y = page_height / 2
c.drawCentredString(x, y, text)
c.save()
packet.seek(0)
return PdfReader(packet)
def add_centered_watermark(input_pdf_path, output_pdf_path, watermark_text):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_centered_watermark(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
This version is useful for “DRAFT” labels or subtle internal-use stamps.
Add an image watermark to a PDF in Python
A logo watermark is a popular branding option. You can place a company logo, seal, or icon onto each page.
Example: watermark with an image
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
def create_image_watermark(image_path, page_width, page_height, opacity=0.2):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
img = ImageReader(image_path)
# Set position and size
img_width = 200
img_height = 80
x = (page_width - img_width) / 2
y = (page_height - img_height) / 2
c.saveState()
c.drawImage(img, x, y, width=img_width, height=img_height, mask='auto')
c.restoreState()
c.save()
packet.seek(0)
return PdfReader(packet)
def add_image_watermark(input_pdf_path, output_pdf_path, image_path):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_image_watermark(image_path, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
add_image_watermark("input.pdf", "watermarked.pdf", "logo.png")
This example places an image in the center of the page. You can easily change the coordinates to move it to the corner, top, or bottom.
Make the image watermark semi-transparent
Image transparency in PDF watermarking can be tricky because not every image format carries alpha in the same way. A reliable approach is to generate a transparent overlay with reportlab or use a PNG with transparency.
Here is a cleaner method using a PNG logo with transparent background.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
def create_logo_watermark(image_path, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
img = ImageReader(image_path)
img_width = 150
img_height = 150
x = page_width - img_width - 30
y = 30
c.drawImage(img, x, y, width=img_width, height=img_height, mask='auto')
c.save()
packet.seek(0)
return PdfReader(packet)
def add_logo_watermark(input_pdf_path, output_pdf_path, image_path):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_logo_watermark(image_path, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
This version is especially useful for branding documents, invoices, proposals, and reports.
Watermark only selected pages
In many projects, you do not need a watermark on every page. You might want to watermark only the first page, only odd pages, or only a page range.
Example: watermark only the first page
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
def create_watermark(text, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.2, 0.2, 0.2, alpha=0.2))
c.setFont("Helvetica-Bold", 36)
c.translate(page_width / 2, page_height / 2)
c.rotate(45)
c.drawCentredString(0, 0, text)
c.save()
packet.seek(0)
return PdfReader(packet)
def watermark_first_page_only(input_pdf_path, output_pdf_path, watermark_text):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_watermark(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for index, page in enumerate(reader.pages):
if index == 0:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
Example: watermark only odd pages
def watermark_odd_pages(input_pdf_path, output_pdf_path, watermark_text):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_watermark(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for index, page in enumerate(reader.pages):
if index % 2 == 0:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
This is useful in publishing workflows or when your design only requires partial branding.
Add a watermark to a specific page range
Sometimes you only want to watermark a section of the document, such as pages 3 through 7.
def watermark_page_range(input_pdf_path, output_pdf_path, watermark_text, start_page, end_page):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_watermark(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for index, page in enumerate(reader.pages, start=1):
if start_page <= index <= end_page:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
Call it like this:
watermark_page_range("input.pdf", "output.pdf", "CONFIDENTIAL", 3, 7)
This can be very useful in document review processes.
Handle different page sizes correctly
Not all PDFs have the same dimensions. Some pages may be A4, while others use Letter or custom sizes. A watermark created for one page size may not fit another page correctly.
To handle this safely, check each page size before applying the watermark.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
def create_watermark_for_page(text, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.4, 0.4, 0.4, alpha=0.18))
c.setFont("Helvetica-Bold", 40)
c.translate(page_width / 2, page_height / 2)
c.rotate(45)
c.drawCentredString(0, 0, text)
c.save()
packet.seek(0)
return PdfReader(packet)
def add_size_aware_watermark(input_pdf_path, output_pdf_path, watermark_text):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
for page in reader.pages:
page_width = float(page.mediabox.width)
page_height = float(page.mediabox.height)
watermark_pdf = create_watermark_for_page(watermark_text, page_width, page_height)
watermark_page = watermark_pdf.pages[0]
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
This approach is safer when your PDF contains mixed page sizes.
Build a reusable watermark utility in Python
In real applications, it is better to wrap watermark logic into a reusable class or module. That way, you can call it from scripts, APIs, or jobs.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
class PDFWatermarker:
def __init__(self, text="CONFIDENTIAL", font_size=40, angle=45, opacity=0.2):
self.text = text
self.font_size = font_size
self.angle = angle
self.opacity = opacity
def _create_watermark_pdf(self, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.5, 0.5, 0.5, alpha=self.opacity))
c.setFont("Helvetica-Bold", self.font_size)
c.translate(page_width / 2, page_height / 2)
c.rotate(self.angle)
c.drawCentredString(0, 0, self.text)
c.save()
packet.seek(0)
return PdfReader(packet)
def add_watermark(self, input_path, output_path):
reader = PdfReader(input_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = self._create_watermark_pdf(page_width, page_height)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_path, "wb") as f:
writer.write(f)
watermarker = PDFWatermarker(text="DRAFT", font_size=48, angle=45, opacity=0.15)
watermarker.add_watermark("input.pdf", "draft_output.pdf")
This class makes the code cleaner and easier to reuse in production.
Add multiple watermarks to a PDF
You may want to place both a text watermark and a logo watermark on the same page. That is common for branded business documents.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
from reportlab.lib.utils import ImageReader
def create_combined_watermark(page_width, page_height, text, image_path):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
# Text watermark
c.setFillColor(Color(0.4, 0.4, 0.4, alpha=0.18))
c.setFont("Helvetica-Bold", 36)
c.translate(page_width / 2, page_height / 2)
c.rotate(45)
c.drawCentredString(0, 0, text)
# Image watermark in bottom-right corner
img = ImageReader(image_path)
c.saveState()
c.drawImage(img, page_width - 120, 20, width=100, height=50, mask='auto')
c.restoreState()
c.save()
packet.seek(0)
return PdfReader(packet)
def add_multiple_watermarks(input_pdf_path, output_pdf_path, text, image_path):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_pdf = create_combined_watermark(page_width, page_height, text, image_path)
watermark_page = watermark_pdf.pages[0]
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as f:
writer.write(f)
This type of combined watermark is often used for official company files.
How to preserve the original layout
When watermarking PDFs, it is important not to break the original document structure. Here are some key tips to keep the layout intact:
Make sure the watermark is transparent enough so text remains readable. Use the correct page dimensions. Avoid placing large objects over important content like charts or forms. Test the output on different PDF viewers. Use vector text whenever possible for cleaner rendering.
A watermark should enhance the document, not damage it.
Common mistakes when adding a PDF watermark in Python
Many developers run into the same problems during implementation.
1. Wrong page size
If the watermark canvas is created with the wrong page size, the watermark may appear off-center or cut off.
2. Too much opacity
A watermark that is too dark can make the document hard to read.
3. Too little opacity
A watermark that is too light may disappear on printed pages.
4. Forgetting rotation
Without rotation, a large watermark may look too plain or overlap the page content awkwardly.
5. Applying the same overlay to mixed page sizes
This can distort the watermark placement.
6. Not checking page order
Some documents are rotated or have different page directions, so the watermark may appear in the wrong spot.
By testing on real PDFs, you can avoid these issues early.
Watermark rotated pages
Some PDFs contain rotated pages. In that case, you may need to inspect the page rotation before watermarking.
from pypdf import PdfReader
reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
rotation = page.get("/Rotate", 0)
print(f"Page {i + 1} rotation: {rotation}")
If the document contains rotated pages, you may need to adapt the watermark placement logic so the watermark still appears in the correct orientation.
Create a command-line watermark script
A simple CLI tool makes watermarking easy to use from the terminal.
import sys
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
def create_watermark(text, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.5, 0.5, 0.5, alpha=0.2))
c.setFont("Helvetica-Bold", 40)
c.translate(page_width / 2, page_height / 2)
c.rotate(45)
c.drawCentredString(0, 0, text)
c.save()
packet.seek(0)
return PdfReader(packet)
def watermark_pdf(input_file, output_file, text):
reader = PdfReader(input_file)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
wm = create_watermark(text, page_width, page_height).pages[0]
for page in reader.pages:
page.merge_page(wm)
writer.add_page(page)
with open(output_file, "wb") as f:
writer.write(f)
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python watermark.py input.pdf output.pdf WATERMARK_TEXT")
sys.exit(1)
input_pdf = sys.argv[1]
output_pdf = sys.argv[2]
watermark_text = sys.argv[3]
watermark_pdf(input_pdf, output_pdf, watermark_text)
Run it like this:
python watermark.py input.pdf output.pdf CONFIDENTIAL
This is a practical option for automation in development and production environments.
Use Python PDF watermarking in web applications
If you build a web app, watermarking can be part of a user workflow. For example:
A user uploads a PDF
Your backend adds a watermark
The system returns a protected version for download
This is common in document management systems, e-learning platforms, invoice generators, and membership portals.
A typical workflow might be:
Receive the uploaded file.
Validate it as a PDF.
Apply watermark processing in the backend.
Save or stream the watermarked document.
Return the final file to the user.
This can be done in Flask, Django, FastAPI, or Laravel with Python-based workers.
Performance considerations
Watermarking a PDF page by page is usually fast enough for normal documents. Still, there are some things to keep in mind:
Large PDFs with many pages can take more memory. Image watermarks may increase file size. Creating a separate watermark page for each page size is more expensive than reusing a shared one. Batch processing should ideally run in background jobs.
For heavy document workloads, keep your watermarking logic simple and avoid unnecessary rendering steps.
Security and compliance use cases
Watermarks are not only for branding. They are also useful for security and compliance. Some examples include:
Internal review documents marked “Confidential”
Legal drafts marked “Attorney Work Product”
Training manuals marked “For Internal Use Only”
Signed PDFs marked with user or company identifiers
Trial documents marked “Sample Copy”
In regulated environments, watermarking can help prevent accidental sharing of sensitive files.
Testing your watermark output
Always test the final PDF in multiple viewers before using it in production. Some viewers may render transparency slightly differently. Print a sample page if printed documents are important in your workflow.
Test for:
Text readability
Proper alignment
Correct page coverage
File integrity
No damage to original content
Expected output on all page sizes
A watermark that looks perfect on screen should also look acceptable in print and on mobile devices.
Full example: complete reusable watermark script
Here is a more polished version you can adapt for your project.
from io import BytesIO
from pypdf import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.colors import Color
class WatermarkTool:
def __init__(self, text="CONFIDENTIAL", font_size=40, angle=45, opacity=0.2):
self.text = text
self.font_size = font_size
self.angle = angle
self.opacity = opacity
def build_watermark(self, page_width, page_height):
packet = BytesIO()
c = canvas.Canvas(packet, pagesize=(page_width, page_height))
c.setFillColor(Color(0.45, 0.45, 0.45, alpha=self.opacity))
c.setFont("Helvetica-Bold", self.font_size)
c.translate(page_width / 2, page_height / 2)
c.rotate(self.angle)
c.drawCentredString(0, 0, self.text)
c.save()
packet.seek(0)
return PdfReader(packet).pages[0]
def watermark(self, input_pdf_path, output_pdf_path):
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
first_page = reader.pages[0]
page_width = float(first_page.mediabox.width)
page_height = float(first_page.mediabox.height)
watermark_page = self.build_watermark(page_width, page_height)
for page in reader.pages:
page.merge_page(watermark_page)
writer.add_page(page)
with open(output_pdf_path, "wb") as output_file:
writer.write(output_file)
if __name__ == "__main__":
tool = WatermarkTool(
text="DRAFT",
font_size=48,
angle=45,
opacity=0.15
)
tool.watermark("input.pdf", "output.pdf")
This version is easy to reuse in projects and can be extended with page ranges, image overlays, or custom positioning.
SEO-friendly use cases for Python PDF watermarking
If you are publishing content or building a tool website, the topic of Python PDF watermarking can support many useful search queries and related articles, such as:
how to add watermark to PDF in Python
Python watermark PDF example
add text watermark to PDF Python
add image watermark to PDF Python
watermark PDF using pypdf
PDF watermark with reportlab
Python PDF editing tutorial
how to protect PDF files with Python
These related terms help search engines understand your content and connect it to user intent.
Final thoughts
Python makes PDF watermarking straightforward, flexible, and automation-friendly. With pypdf and reportlab, you can create professional text watermarks, image watermarks, diagonal overlays, page-specific stamps, and reusable watermark utilities for real-world apps.
The key idea is simple: create a watermark layer, then merge it into the original PDF page by page. Once you understand that pattern, you can customize it for branding, security, legal documents, internal drafts, or customer-facing files.
Hassan Agmir
Author · Filenewer
Writing about file tools and automation at Filenewer.
Try It Free
Process your files right now
No account needed · Fast & secure · 100% free
Browse All Tools