DEV Community

Cover image for Fill Existing PDF Forms from n8n Without Rebuilding the Template
Maciej Śnieżyński
Maciej Śnieżyński

Posted on Fully Autonomous

Fill Existing PDF Forms from n8n Without Rebuilding the Template

An earlier version of this n8n workflow had a bad fallback: when it couldn't find an exact PDF field name, it tried a partial match. For example, an input called total could match a field called subtotal if there was no exact match.

The PDF would still be generated. The number would just be in the wrong box.

That fallback is gone in the current version. Below is the corrected workflow, a three-field PDF you can test it with, and what the latest test actually covered. I build JustFill, the PDF service used here.

Where the mapping went wrong

The old mapping node used find() with a substring fallback. It also stripped everything outside a-z and 0-9 when comparing names, which lost non-ASCII letters.

The replacement keeps Unicode letters and requires an exact match after normalization. This is the matching part of the Code node, not the complete node:

const norm = s => String(s ?? '')
  .normalize('NFC')
  .toLowerCase()
  .replace(/[^\p{L}\p{M}\p{N}]+/gu, '');

const nk = norm(k);
const matches = ws.fields.filter(f => norm(f.name) === nk);
Enter fullscreen mode Exit fullscreen mode

So Company Name and company_name match; total and subtotal don't. If normalization gives two PDF fields the same name, the workflow rejects the ambiguity rather than choosing the first one.

The rest of the node rejects unknown input keys, two keys targeting one field, arrays, and nested objects. null writes a blank value. A PDF field left out of the input is optional; this code doesn't decide which fields your business process requires.

This still depends on the template being right. A correctly named field in the wrong place will produce a correctly matched value in the wrong place. Review the boxes once for each PDF version and save that layout before using it for recurring documents.

Try it with a supplier-intake PDF

Download the current workflow JSON from GitHub and use Workflows → Import from File in n8n. The catalog update was submitted for review on September 5, 2026. While the n8n listing is temporarily unavailable, use the repository file for this example.

The workflow fills the PDF you upload. It doesn't rebuild the document from HTML. It uses HTTP Request and Code nodes, so you don't need to install a community node or configure an LLM key.

Form Trigger (PDF + JSON)
  → request a one-time upload URL
  → POST the PDF binary
  → open_pdf
  → map field names
  → fill_pdf
  → redirect to the download URL
Enter fullscreen mode Exit fullscreen mode

Create a JustFill key under Account → API keys and put it in the Config node for the test. That node stores the key in the workflow definition: don't share an export with the key inside it. For production, move it to an n8n credential or environment variable. The requests go to https://justfill.app/api/mcp as JSON-RPC over HTTP; the imported nodes already build the request bodies.

Open the form trigger's test URL, upload the sample supplier-intake PDF, and paste:

{
  "company_name": "Northwind LLC",
  "vendor_reference": "V-1042",
  "remittance_email": "ap@northwind.example"
}
Enter fullscreen mode Exit fullscreen mode

This sample has three named AcroForm fields, so it doesn't need a separate template-preparation step. All values are synthetic. In the output, check the company, reference, and email boxes individually, then try adding unknown_field to the JSON. That second run should stop before filling.

Supplier-intake PDF with the company, reference, and email filled in

Historical watermarked example showing the three field positions, not the clean output from the September 5 test.

What has actually been tested

The September 5, 2026 check ran the workflow's actual mapping code against production MCP upload, open, and fill responses. All three values appeared in the expected boxes in a clean PDF, which was also checked visually. An extra unknown key was rejected before filling. The temporary workspace and credential were removed afterward.

That was an HTTP-plus-Code-node test, not a new run inside the n8n engine. The cover image is from the earlier full workflow run on n8n 2.28.6, on July 20; it is not evidence of the September strict-mapping update.

You can run the mapping regression tests without n8n or an API key. From a checkout of the public justfill-mcp repository:

node --test examples/n8n/test-deterministic-mapping.mjs
Enter fullscreen mode Exit fullscreen mode

The three-field test doesn't establish that a dense, multipage form will be laid out correctly. Test your actual PDF with synthetic values, including long text and any checkboxes, before connecting customer data.

Connecting your own data

For a recurring supplier form, replace the Form Trigger with your procurement webhook and construct just the three fields the PDF needs. Don't feed the mapper a whole supplier record: extra keys will now fail the run deliberately.

Replace the final redirect with your delivery step. Check output_mode before sending anything: it can be clean or watermarked. The download link is temporary, so if you need an archive, fetch the PDF and store it in your own destination.

The n8n setup guide collects the import files and template instructions. If your data is already a spreadsheet and you don't need n8n around it, the five-row Excel/CSV browser sample is a shorter way to check whether your PDF works.

Disclosure: I am the solo developer of JustFill.

AI disclosure: AI coding agents drafted and revised this article and ran the code checks described above.

Top comments (0)