Last modified: Feb 07, 2026 By Alexander Williams

Add Text Overlay to PDF Pages with Python

Working with PDFs is a common task. You might need to add notes, stamps, or watermarks. Doing this manually for many files is slow and error-prone.

Python offers powerful libraries to automate this. You can programmatically add text to any page. This guide will show you how.

We will use two popular libraries: PyPDF2 and reportlab. You will learn to create new PDFs with text and merge them with originals.

Why Add Text Overlays Programmatically?

Manual editing is not scalable. Imagine adding page numbers to a 100-page report. Or applying a "CONFIDENTIAL" stamp to hundreds of invoices.

Python automation saves time and ensures consistency. It is perfect for batch processing. You can integrate it into larger data workflows.

Common use cases include adding timestamps, annotations, disclaimers, or dynamic data. It is a key skill for document automation.

Understanding the Overlay Technique

We cannot directly edit text onto an existing PDF page like a word processor. PDFs are a final-format document.

The standard technique involves creating a new PDF layer. This layer contains only the text you want to add. You then merge this new layer on top of your original PDF page.

Think of it like placing a transparent sheet with text over your document. The original content remains untouched underneath.

Setting Up Your Python Environment

First, ensure you have Python installed. Then, install the necessary libraries using pip. We will use PyPDF2 for PDF manipulation and reportlab for creating the text layer.


pip install PyPDF2 reportlab
    

If you need to convert PDF pages to images for more complex operations, our Python PDF to Image Conversion Guide can help.

Method 1: Using PyPDF2 and reportlab

This is a reliable method. We use reportlab to draw text onto a blank page that matches your PDF's size. Then, PyPDF2 merges them.

Let's write a function to add a simple text watermark to the first page.


from PyPDF2 import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io

def add_text_overlay(input_pdf_path, output_pdf_path, text, x, y):
    """
    Adds a text overlay to the first page of a PDF.
    
    Args:
        input_pdf_path (str): Path to the original PDF.
        output_pdf_path (str): Path to save the new PDF.
        text (str): The text to overlay.
        x (int): X-coordinate for text (points from left).
        y (int): Y-coordinate for text (points from bottom).
    """
    
    # Step 1: Read the original PDF
    reader = PdfReader(input_pdf_path)
    writer = PdfWriter()
    
    # Get dimensions of the first page
    first_page = reader.pages[0]
    page_width = float(first_page.mediabox.width)
    page_height = float(first_page.mediabox.height)
    
    # Step 2: Create a new PDF with reportlab containing our text
    packet = io.BytesIO()
    can = canvas.Canvas(packet, pagesize=(page_width, page_height))
    can.setFont("Helvetica", 20)  # Set font and size
    can.setFillColorRGB(1, 0, 0, alpha=0.5)  # Red color, 50% transparent
    can.drawString(x, y, text)  # Draw the text at coordinates
    can.save()
    
    # Step 3: Move to the beginning of the BytesIO buffer
    packet.seek(0)
    new_pdf = PdfReader(packet)
    overlay_page = new_pdf.pages[0]
    
    # Step 4: Merge the overlay page with the original page
    first_page.merge_page(overlay_page)
    
    # Step 5: Add the modified page to the writer
    writer.add_page(first_page)
    
    # Add the rest of the original pages unchanged
    for page_num in range(1, len(reader.pages)):
        writer.add_page(reader.pages[page_num])
    
    # Step 6: Write the output PDF file
    with open(output_pdf_path, 'wb') as output_file:
        writer.write(output_file)
    
    print(f"Overlay added. New PDF saved to: {output_pdf_path}")

# Example Usage
add_text_overlay("original.pdf", "output_with_overlay.pdf",
                 "DRAFT", 250, 500)
    

The add_text_overlay function does the heavy lifting. It reads the original, creates a text layer, and merges them. The coordinates (x, y) are in points, measured from the bottom-left corner.

For more control over PDF metadata before or after adding overlays, see our guide on Python PdfWriter.add_metadata: Add PDF Metadata.

Adding Text to Multiple Pages

The previous example only modified the first page. To add text to every page, you need a loop. You can also vary the text or position per page.

Here is how to add a page number to the bottom center of every page.


def add_page_numbers(input_pdf_path, output_pdf_path):
    """Adds page numbers to all pages of a PDF."""
    
    reader = PdfReader(input_pdf_path)
    writer = PdfWriter()
    
    for page_num, page in enumerate(reader.pages):
        page_width = float(page.mediabox.width)
        page_height = float(page.mediabox.height)
        
        packet = io.BytesIO()
        can = canvas.Canvas(packet, pagesize=(page_width, page_height))
        can.setFont("Helvetica", 12)
        text = f"Page {page_num + 1}"
        # Center the text horizontally, 50 points from bottom
        text_width = can.stringWidth(text, "Helvetica", 12)
        x = (page_width - text_width) / 2
        y = 50
        can.drawString(x, y, text)
        can.save()
        
        packet.seek(0)
        overlay_pdf = PdfReader(packet)
        overlay_page = overlay_pdf.pages[0]
        
        page.merge_page(overlay_page)
        writer.add_page(page)
    
    with open(output_pdf_path, 'wb') as f:
        writer.write(f)
    
    print(f"Page numbers added. File saved: {output_pdf_path}")

# Usage
add_page_numbers("report.pdf", "report_numbered.pdf")
    

Advanced Customization and Tips

The reportlab library is very powerful. You are not limited to simple text.

You can change fonts, colors, rotation, and transparency. You can even draw shapes or images around your text.


# Example of advanced text styling in reportlab
can.setFont("Times-BoldItalic", 36)
can.setFillColorRGB(0.2, 0.4, 0.8) # RGB color
can.setFillAlpha(0.7) # Transparency
can.rotate(45) # Rotate text 45 degrees
can.drawString(100, 300, "WATERMARK")
can.rotate(-45) # Reset rotation for other drawings
    

Coordinate System: Remember, (0,0) is the bottom-left. This is different from many image libraries. Use the page dimensions to calculate positions.

Performance: For PDFs with many pages, processing can take a moment. The operation is linear to the number of pages.

If your workflow involves merging multiple PDFs after processing, techniques from Python PdfFileMerger.write: Merge PDFs Easily will be useful.

Common Challenges and Solutions

Text Not Appearing: Double-check your coordinates. The text might be drawn outside the visible page area. Print the page width and height to debug.

Wrong Font: reportlab has a limited set of standard fonts. For custom fonts, use pdfmetrics.registerFont and TTFont.

Low Text Quality: PDF text is vector-based and should be sharp. If it appears pixelated, ensure you are not accidentally converting the page to an image first.

Overwriting Content: The overlay sits on top. If it covers important information, adjust the coordinates or reduce the alpha (transparency) value.

Conclusion

Adding text overlays to PDFs with Python is straightforward. The PyPDF2 and reportlab combination is effective for most tasks.

You learned the core technique: create a text layer and merge it. We covered adding text to single and multiple pages with customization.

This skill unlocks powerful document automation. You can batch process reports, certify documents, or add dynamic data.

Start by experimenting with the example code. Adjust the text, position, and style to fit your needs. Automating this task will save you countless hours.