Your e-signature provider hands back the finished packet and you want the answers, not the pixels. If the completed PDF still carries live AcroForm fields, pypdf reads them straight off the document:
from pypdf import PdfReader
reader = PdfReader("completed-packet.pdf")
fields = reader.get_fields()
if not fields:
raise SystemExit("No form fields left: this PDF has been flattened.")
for name, field in fields.items():
print(f"{name}\ttype={field.get('/FT')}\tvalue={field.get('/V')!r}")Against a filled packet, that prints:
full_name type=/Tx value='Dana Reyes'
title type=/Tx value='CTO'
agree_terms type=/Btn value='/Yes'
signed_date type=/Tx value='2026-08-10'/FT is the field type and /V is the field's value, whose format varies by type. Text and choice fields hand back strings. Button fields (/Btn, meaning checkboxes and radio groups) hand back a PDF name such as /Yes, so compare it against the checked-state name your form actually uses rather than casting it to a boolean. Fields nested under a parent come back under their fully qualified name with each parent separated by a dot, so two fields both named city show up as sender.city and receiver.city.
When there are no fields left to read
The common surprise is that get_fields() comes back empty. Flattening a form keeps all the field contents while removing the form fields themselves, converting them into ordinary page content. Once that has happened the values are drawings, and there is no field layer left to query. Resist the urge to rebuild them by extracting the page text and matching labels to nearby values; that gets brittle fast and fails quietly. Take the values from your provider instead. The completion webhook payload and the field-data endpoint both give you what the signer typed as structured data, which is what you actually wanted to store.
Treat the PDF as the artifact, not the record
Even when the fields survive, /V is writable. pypdf's own update_page_form_field_values rewrites field values in a few lines, and so will any desktop PDF editor. That is fine for the signed copy you archive, but it means the PDF is a weak system of record. Store the structured values from your provider alongside the file, and reconcile against those.
The pypdf forms documentation covers the reader and writer sides in more detail, including how widget annotations relate to the field objects you get back.
Back to All Questions