Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
PDFs
Categories

Why do the form fields disappear when I merge filled PDFs, and how do I fix it?

You merge two filled PDF forms into one file, open the result, and the fields are gone. Nothing is selectable, the values you filled in do not show, and reading the merged file programmatically returns no fields at all. Both source files were fine on their own.

The cause: the form is attached to the document, not the page

A PDF form has two halves. The visible boxes are widget annotations sitting in each page's /Annots array. The form itself, the /AcroForm dictionary that holds the /Fields array, hangs off the document catalog (the root object) rather than off any page.

Copy pages from one file into another and you carry the widgets across while leaving the /AcroForm behind. The result is a document with orphaned widget annotations and no form. The pypdf documentation puts it plainly: fields are not stored in pages, so add_page() does not copy the field structure.

The fix: merge at the document level

In pypdf, use append() instead of looping over pages:

from pypdf import PdfReader, PdfWriter

# Loses the form: this copies pages only.
writer = PdfWriter()
for path in ("a.pdf", "b.pdf"):
    for page in PdfReader(path).pages:
        writer.add_page(page)
writer.write("broken.pdf")
print(list((PdfReader("broken.pdf").get_fields() or {}).keys()))

# Keeps the form: append() carries the AcroForm across.
writer = PdfWriter()
writer.append("a.pdf")
writer.append("b.pdf")
writer.write("merged.pdf")
print(list(PdfReader("merged.pdf").get_fields().keys()))

The first block prints an empty list. The second prints ['a_name', 'b_name'].

Second gotcha: identical field names collapse into one field

If both source files came from the same template, their fields carry the same names, and in PDF the field name is the field's identity. Append two copies of a template that has a "name" field and you get one field with two widgets, one on each page. Set its value and both pages change together.

Give the fields unique names as you append:

from pypdf import PdfReader, PdfWriter
from pypdf.generic import NameObject, TextStringObject

writer = PdfWriter()
for prefix, path in (("copy1_", "c1.pdf"), ("copy2_", "c2.pdf")):
    start = len(writer.pages)
    writer.append(path)
    for page in writer.pages[start:]:
        for annot in page.get("/Annots", []):
            obj = annot.get_object()
            if obj.get("/Subtype") == "/Widget" and "/T" in obj:
                obj[NameObject("/T")] = TextStringObject(prefix + obj["/T"])
writer.write("renamed.pdf")

print(list(PdfReader("renamed.pdf").get_fields().keys()))

That prints ['copy1_name', 'copy2_name'] instead of ['name'].

Two caveats. The loop above only renames widgets that carry their own /T, so a template whose field names live on parent nodes in a field hierarchy needs the parent renamed instead. And if nobody has to edit the merged file, flatten each document before merging: flattening turns field contents into ordinary page content, so there is no form state left to lose.

Tested with pypdf 6.15.0.

Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms