COMING SOON: Spring 2026 Release Arrives April 15th
Garry Klooesterman
Senior Technical Content Creator
Published April 09, 2026
Updated April 09, 2026
5 min
Garry Klooesterman
Senior Technical Content Creator

Summary: Manually managing PDF forms at scale often leads to values that exist in the file but fail to appear in the viewer. This post explores how to programmatically bridge the gap between the logical Field layer and the visual Widget layer using the Apryse Server SDK. You'll learn why relying on the NeedAppearances flag is a risky shortcut, how to use XFDF for high-speed database-to-PDF workflows, and the steps to flatten and export professional-grade documents in C# and Java.

Filling a PDF form should be as simple as setting a variable but in reality, developers often encounter users opening a generated PDF in a browser or mobile viewer, and the fields look completely blank until the user clicks on them. This happens because of a disconnect in the PDF's internal structure between the data and its visual representation. In enterprise environments where documents like W-9s, contracts, or permits must be legally binding and visually consistent, clicking to see data isn't an option.
To solve this, we need to do more than just basic form filling and understand how to incorporate data directly into the document's visual layer. Using the Apryse Server SDK, we can programmatically control this process. This blog will look at the difference between Fields and Widgets, show you how to leverage XFDF for bulk processing, and provide the C# and Java code needed to ensure your exported PDFs look exactly the same on a screen as they do on a printed page.
Most people think a field is just a box on a page. In reality, a PDF splits these into two parts:
The problem is that if you update the Field value but don't call RefreshAppearance(), the PDF might contain your data, but the Widget will keep showing its old, cached visual or nothing at all. Relying on the NeedAppearances flag is notoriously unreliable and causes "Save Changes" prompts to pop up for the user.
If you're dealing with hundreds of records, you don't want to loop through fields manually. Instead, you can use XFDF. It’s essentially an XML representation of your form data.
You can extract data from a filled PDF into an XFDF string or take a string from your database and inject it into a blank template in one shot. It’s significantly faster for batch processing.
Here is the order of the process for what’s happening:
It comes down to who owns the design:
Getting started on this project requires just a few steps before we can get into the main how to of the blog.
For the examples in this blog, I’ll be using C# and Java, but the code is available in other languages as well, like Python, C++, and JavaScript.
Now, let’s look at the code we’ll need for our project. The pattern is the same in both languages: load the doc, find the field by its "fully qualified name" (like employee.name.first), and update it.
That was the C# example. Now, let’s look at the Java version of the same code.
See our full Flatten, Create, Modify PDF Forms – Interactive Forms code sample for more details.
Let’s take a look at the code above, section by section, and see what each part does.
I’m only reviewing the C# code, but the Java code follows the same logic.
This is the critical part to finding the field we want to update and setting the value. Don’t forget to refresh the appearance of the field to show the value after we’ve set it.
For checkboxes, we’re checking to see if the checkbox exists and if it does, we set the value to “check” the box.
We check to see if the combo box exists and if it does, we set the value to “select” an item from the list.
For radio buttons, we do basically the same thing as with the other 2 options: we check to see if it exists and then if it does, set the value to “select” the option we want.
Now we want to flatten the document to make it permanent and secure so that it can’t be edited.
// Flattening makes the data "permanent" and uneditable
doc.FlattenAnnotations(true); And last, save the document.
doc.Save("output.pdf", SDFDoc.SaveOptions.e_linearized); What if I have two fields with the same name?
In a PDF, if two fields share the same name, they share the same value. Updating one will update the other automatically. This is actually a great way to handle "Name" fields that appear on every page of a long contract.
How do I find all the field names in a mystery PDF?
Use a FieldIterator. You can loop through the document and print field.GetName() to see exactly what strings you need to target in your code.
Is there a way to make fields "Read Only" without flattening?
Yes. You can use field.SetFlag(Field.e_read_only, true). This keeps the "Form" structure intact but prevents the user from typing in the boxes.
Does this work for Digital Signatures?
Signatures are a special type of form field. You can create a SignatureWidget programmatically, but filling it usually involves a certificate-based signing process rather than a simple text value.
What is the "e_linearized" save option?
It's often called "Fast Web View." It optimizes the PDF so that the first page can be displayed in a browser while the rest of the file is still downloading in the background. Highly recommended for web apps.
Successful server-side form filling is about ensuring document integrity across the entire digital lifecycle. By moving away from unreliable shortcuts like the NeedAppearances flag and manually refreshing your appearance streams, you eliminate the risk of empty fields and inconsistent rendering.
Whether you are populating a single application or batch-processing thousands of records using XFDF, the goal remains the same: a final, flattened document that serves as a tamper-proof and professional record.
The Apryse Server SDK simplifies this process into a few lines of code, allowing you to focus on your data.
Contact our sales team for any questions and support.
PRODUCTS
Platform Integrations
End User Applications
Popular Content
RESOURCES
// Initialize your library
PDFNet.Initialize("YOUR_LICENSE_KEY");
using (PDFDoc doc = new PDFDoc("template.pdf"))
{
doc.InitSecurityHandler();
// Finding a field (use FieldIterator if you aren't sure of the names)
Field fld = doc.GetField("employee.last_name");
if (fld != null)
{
fld.SetValue("Evans");
// CRITICAL: Don't skip this or the field might look blank
fld.RefreshAppearance();
}
// Checkboxes use booleans
Field check = doc.GetField("employee.agreed");
if (check != null)
{
check.SetValue(true);
check.RefreshAppearance();
}
// Dropdowns (Combo Boxes): Pass the string of the option you want to select
Field combo = doc.GetField("employee.department");
if (combo != null)
{
// Ensure the value matches exactly one of the options in the dropdown list
combo.SetValue("Engineering");
combo.RefreshAppearance();
}
// Radio Buttons: Pass the string value of the specific option to select it
Field radio = doc.GetField("employee.membership_level");
if (radio != null)
{
radio.SetValue("Gold");
radio.RefreshAppearance();
}
// Flattening makes the data "permanent" and uneditable
doc.FlattenAnnotations(true);
doc.Save("output.pdf", SDFDoc.SaveOptions.e_linearized);
} // Initialize the SDK
PDFNet.initialize("YOUR_LICENSE_KEY");
try (PDFDoc doc = new PDFDoc("template.pdf")) {
doc.initSecurityHandler();
// Locate the field by name
Field fld = doc.getField("employee.last_name");
if (fld != null) {
fld.setValue("Evans");
// CRITICAL: Don't skip this or the field might look blank
fld.refreshAppearance();
}
// Checkboxes: Use a boolean to check or uncheck the box
Field check = doc.getField("employee.agreed");
if (check != null) {
check.setValue(true);
check.refreshAppearance();
}
// Dropdowns (Combo Boxes): Pass the string of the option you want to select
Field combo = doc.getField("employee.department");
if (combo != null) {
// Ensure the value matches exactly one of the options in the dropdown list
combo.setValue("Engineering");
combo.refreshAppearance();
}
// Radio buttons and Checkboxes
Field radio = doc.getField("employee.membership_level");
if (radio != null) {
radio.setValue("Gold");
radio.refreshAppearance();
}
// Flattening turns the form into a static document
doc.flattenAnnotations(true);
doc.save("output.pdf", SDFDoc.SaveOptions.E_linearized, null);
} catch (Exception e) {
// Handle exceptions
} // Finding a field (use FieldIterator if you aren't sure of the names)
Field fld = doc.GetField("employee.last_name");
if (fld != null)
{
fld.SetValue("Evans");
// CRITICAL: Don't skip this or the field might look blank
fld.RefreshAppearance();
} // Checkboxes use booleans
Field check = doc.GetField("employee.agreed");
if (check != null)
{
check.SetValue(true);
check.RefreshAppearance();
} // Dropdowns (Combo Boxes): Pass the string of the option you want to select
Field combo = doc.GetField("employee.department");
if (combo != null)
{
// Ensure the value matches exactly one of the options in the dropdown list
combo.SetValue("Engineering");
combo.RefreshAppearance();
} // Radio Buttons: Pass the string value of the specific option to select it
Field radio = doc.GetField("employee.membership_level");
if (radio != null)
{
radio.SetValue("Gold");
radio.RefreshAppearance();
}