Skip to content

PDF Form Fields

Pull the filled values out of AcroForm/XFA PDFs as structured fields you can forward to downstream systems — extract checkboxes, text inputs, dropdowns, radio buttons, and signature fields directly without OCR.

Fillable PDFs store form structure in two ways:

  • AcroForm — Static form specification with field metadata. Fully supported.
  • XFA — XML-based dynamic forms. Fully supported. When a document carries both layers, AcroForm fields are extracted first and XFA-only fields are appended.

Extracted fields appear in result.form_fields as a list of PdfFormField structs, each carrying:

Property Type Description
name string Leaf field name in the hierarchy (e.g., "line_total").
full_name string Dotted path from root (e.g., "invoice.line_items[0].line_total").
field_type enum One of: Text, Checkbox, Radio, Choice, Signature, Button, Unknown.
value string Current field value (if filled).
default_value string Default value from the form template.
flags u32 Bitmask: read-only, required, multiline, password, and so on.
page Option<u32> 1-indexed page number the field appears on. Currently always None — page assignment is not yet wired up.
bbox BoundingBox Widget location on the page (x, y, width, height).
max_length u32 Maximum input length (text fields only).
tooltip string Hover text or field description.

Enable form field extraction (default):

xberg.toml
[pdf]
extract_form_fields = true

Disable (to skip form processing):

[pdf]
extract_form_fields = false
from xberg import ExtractInput, extract, ExtractionConfig, PdfConfig
config = ExtractionConfig(
pdf_options=PdfConfig(extract_form_fields=True)
)
output = await extract(ExtractInput(kind="uri", uri="form.pdf"), config=config)
result = output.results[0]
for field in result.form_fields:
print(f"Field: {field.full_name} = {field.value or '(empty)'}")
print(f" Type: {field.field_type}, Page: {field.page}")

Form Auto-Fill

Extract field values to populate templates or CRMs:

output = await extract(ExtractInput(kind="uri", uri="invoice_form.pdf"))
result = output.results[0]
form_data = {f.full_name: f.value for f in result.form_fields if f.value}
# Submit form_data to downstream system

Form Validation

Check required fields and validate data before processing:

required_fields = {f for f in result.form_fields if f.flags & 0x02} # Check required bit (0x01 is read-only)
unfilled = {f.full_name for f in required_fields if not f.value}
if unfilled:
print(f"Missing required fields: {unfilled}")

Form-to-Data Conversion

Convert fillable forms to structured JSON:

form_json = {
f.full_name: {
"value": f.value,
"type": f.field_type,
"page": f.page,
"bbox": f.bbox
}
for f in result.form_fields
}
  • Page numbers — The page field is currently always None; page assignment via spatial analysis is not yet wired up. Use bbox for on-page positioning.
  • Flattened PDFs — If form content is rendered into the PDF content stream (vs. stored as field metadata), the form structure is lost. Only editable/unfilled forms preserve field metadata.
  • Appearance streams — Custom visual styling (button backgrounds, text colors) is not extracted; field values and types only.
  1. Check field types — Use field_type to handle different input types (text vs. checkbox vs. dropdown).
  2. Validate input — Check max_length and format requirements before use.
  3. Preserve layout — Use bbox to reconstruct form layout programmatically (page is not yet populated).
  4. Default values — When a field has no value, consider using default_value as fallback.
  5. Test on real forms — Form structures vary; test your extraction logic on representative PDFs from your sources.