# PDF Forms: Read and Fill AcroForm Fields with Python
Interactive PDF forms (AcroForm) are common in official documentation, contracts, and applications. Python lets you read, fill, and create them automatically.
## AcroForm Field Types
| Type | Description |
|---|---|
| **TextField** | Free text input |
| **CheckBox** | Check box |
| **RadioButton** | Radio button (group) |
| **ComboBox** | Dropdown list |
| **ListBox** | Multi-selection list |
| **Signature** | Digital signature field |
## Read Form Fields with pypdf
```bash
pip install pypdf
```
```python
from pypdf import PdfReader
reader = PdfReader("form.pdf")
# Text fields
fields = reader.get_form_text_fields()
for name, value in fields.items():
print(f" {name!r}: {value!r}")
# All field types
for name, field in reader.get_fields().items():
field_type = field.get('/FT', '?')
value = field.get('/V', '')
print(f" [{field_type}] {name}: {value}")
```
## Fill an Existing Form
```python
from pypdf import PdfReader, PdfWriter
reader = PdfReader("blank_form.pdf")
writer = PdfWriter()
writer.append(reader)
data = {
"full_name": "Maria Garcia",
"id_number": "12345678A",
"email": "maria@example.com",
"city": "Madrid",
}
for page in writer.pages:
writer.update_page_form_field_values(page, data)
with open("filled_form.pdf", "wb") as f:
writer.write(f)
print("Saved: filled_form.pdf")
```
### Checkboxes and Radio Buttons
```python
data = {
"name": "John Smith",
"accept_terms": "Yes", # Checkbox: "Yes" = checked
"gender": "/Male", # RadioButton: widget value
"country": "US", # ComboBox: option value
}
for page in writer.pages:
writer.update_page_form_field_values(page, data)
```
## Create PDF Form from Scratch with reportlab
```bash
pip install reportlab
```
```python
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def create_form(output="new_form.pdf"):
c = canvas.Canvas(output, pagesize=A4)
width, height = A4
c.setFont("Helvetica-Bold", 18)
c.drawString(50, height - 60, "Registration Form")
c.setFont("Helvetica", 12)
c.drawString(50, height - 110, "Full Name:")
c.acroForm.textfield(name="full_name", x=200, y=height-120, width=300, height=20)
c.drawString(50, height - 150, "Email:")
c.acroForm.textfield(name="email", x=200, y=height-160, width=300, height=20)
c.drawString(50, height - 200, "Accept terms:")
c.acroForm.checkbox(name="accept_terms", x=210, y=height-210, buttonStyle="check")
c.drawString(50, height - 250, "Country:")
c.acroForm.choice(
name="country",
options=[("US","United States"),("GB","UK"),("CA","Canada"),("AU","Australia")],
x=200, y=height-260, width=200, height=20, value="US",
)
c.drawString(50, height - 300, "Gender:")
c.acroForm.radio(name="gender", tooltip="Male", x=200, y=height-310,
buttonStyle="circle", value="Male")
c.drawString(225, height - 305, "Male")
c.acroForm.radio(name="gender", tooltip="Female", x=300, y=height-310,
buttonStyle="circle", value="Female")
c.drawString(325, height - 305, "Female")
c.save()
print(f"Form created: {output}")
create_form()
```
## Fill with pdfrw
```bash
pip install pdfrw
```
```python
import pdfrw
def fill_pdfrw(input_path, output_path, data):
template = pdfrw.PdfReader(input_path)
for page in template.pages:
annotations = page.get('/Annots') or []
for a in annotations:
if a.get('/Subtype') == '/Widget' and a.get('/T'):
name = a['/T'][1:-1]
if name in data:
a.update(pdfrw.PdfDict(V=data[name], AP=''))
template.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
pdfrw.PdfWriter().write(output_path, template)
print(f"Saved: {output_path}")
fill_pdfrw("template.pdf", "filled.pdf", {
"name": "Anna Torres",
"email": "anna@example.com",
})
```
## Flatten the Form (Form to Static)
```python
# Method 1: pypdf
from pypdf import PdfReader, PdfWriter
reader = PdfReader("filled_form.pdf")
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
with open("flattened.pdf", "wb") as f:
writer.write(f)
# Method 2: Ghostscript (more faithful)
import subprocess
subprocess.run([
"gs", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pdfwrite",
"-dFlattenForm", "-sOutputFile=flattened_gs.pdf", "filled_form.pdf"
], check=True)
```
## Extract Data from Filled Form
```python
from pypdf import PdfReader
import json
reader = PdfReader("filled_form.pdf")
extracted = {}
for name, field in reader.get_fields().items():
value = field.get('/V', '')
if hasattr(value, 'get_object'):
value = str(value.get_object())
extracted[name] = str(value) if value else ""
print(json.dumps(extracted, indent=2))
```
## Tools for Creating Form Templates
| Tool | Type | AcroForm |
|---|---|---|
| Adobe Acrobat | Paid | Full |
| LibreOffice Draw | Free | Basic |
| PDFescape | Online | Free basic |
| reportlab | Python | Programmatic |
## Convert Online
To fill or extract data from PDF forms without Python, KaijuConverter processes PDFs directly in the browser.
Guide