Best HTML to PDF APIs for Fillable Forms: 6 APIs Tested on the Same Form
Blog / HTML to PDF
HTML to PDF

Best HTML to PDF APIs for Fillable Forms: 6 APIs Tested on the Same Form

Demetra Theodorou · Oct 19, 2026

We built a two-page onboarding form and sent it to the six HTML to PDF APIs that can create fillable fields, then we went through every field in the output to see which types, names, defaults and flags made it across, and whether the result could still be filled in and flattened.

A PDF can look like a form without actually being one. If the fields are real, other software can read their names, their values and their rules. If they are just drawn boxes, nobody can do anything with them. When we put together our roundup of HTML to PDF APIs, only a handful of services could create real fields at all. So this time we wanted to know something more specific. When you hand one of those services an HTML form, how accurately does it end up in the PDF?

We wrote a two-page customer onboarding form and gave every input a job, which is to catch one detail that converters tend to lose. Our form includes a required name, a pre-filled email, a read-only customer ID, a number and a date, a country dropdown with one country already chosen, three plan options with one already picked, one ticked and one unticked checkbox, and two free-text boxes. Page two adds a password. At the very end there is a plain bordered signature line. It is not an input, so it should stay a drawn line in the PDF. If a converter turns it into a field, it is creating fields where there are none.

Page 1 of the test form as plain Chrome rendered it: account details, plan and agreements sections

Page 1 of the test form, rendered by plain Chrome, which creates no fields.

Then we sent the form to all six APIs and let a script look at what came back, because eyes are easy to fool. The script opens each PDF with pdf-lib and goes through the fields one by one, checking type, name, value, options, flags and which page they landed on. At the end it fills the whole form in, reads the values back out and flattens the document, the way a real application would. That adds up to 17 checks per PDF.

Everything is public. The form, the runner, the check script and every generated PDF are in the repository, so you can look at the outputs yourself or point the whole thing at your own form.

The results

APIHow fields are createdHTML changesChecksAverage timeFile sizePrice
PDFGateStandard inputs, one optionNone17/171.6 s126 KBFrom $9/month, 14-day trial
PDFCrowdStandard inputs, one optionNone16/172.7 s149 KB100 trial credits, then from $1/month
DocRaptorPrince CSS rule on the inputs3 lines16/172.2 s*36 KB5 free documents/month, then from $15/month
jsreport onlineTemplate helpers instead of inputs37 lines13/170.6 s33 KBFree plan with 200 credits, then from $29.95/month
PDFMonkeyText markers instead of inputs41 lines12/177.2 s81 KB20 free documents/month, then from €5/month
Nutrient DWSStandard inputs, no option neededNone8/171.1 s91 KB50 free credits/month, then from €63/month on a yearly plan

A few notes on the table. Everything was generated on A4 with fields switched on wherever there is a switch. The times are averages over five requests, measured from the moment we sent the request to the moment we had the PDF. DocRaptor gets an asterisk because we timed it in its free test mode and used a single production request, which took 2.5 seconds, for the output file. “HTML changes” is simply how many lines differ between our form and the version each service needed.

And here is how that breaks down, check by check:

CheckPDFGatePDFCrowdDocRaptorjsreport onlinePDFMonkeyNutrient DWS
F1 Text inputs become text fields✅✅✅✅✅❌
F2 Textarea becomes a multiline field✅✅✅✅✅❌
F3 Select becomes a dropdown with all 5 options✅✅✅✅✅✅
F4 Select default option kept✅✅✅✅❌✅
F5 Radios become one group with 3 options✅✅✅❌✅✅
F6 Radio default kept✅✅✅❌❌✅
F7 Checkboxes become checkboxes✅✅✅✅✅✅
F8 Checked state kept✅❌✅✅❌✅
F9 Pre-filled text value kept✅✅✅✅❌❌
F10 Field names match the HTML name attribute✅✅❌❌❌❌
F11 required kept✅✅✅✅✅❌
F12 readonly kept✅✅✅✅✅❌
F13 Number and date inputs become fields✅✅✅✅✅❌
F14 Password input masks what is typed✅✅✅✅✅✅
F15 Page-2 fields are on page 2✅✅✅✅✅❌
F16 Exactly the 12 fields, no strays✅✅✅❌✅❌
F17 Fill with pdf-lib, read back, flatten✅✅✅✅✅✅
Score17/1716/1716/1713/1712/178/17

One thing to know about how the matching works. A field counts as “the customer ID field” if it has the HTML name, or a renamed version that the API documents. So Nutrient's customer_id_customer_id and DocRaptor's Form1.customer_id both pass the checks about type and value. Whether the name survived untouched is a separate question, and that is what the F10 checks.

Where the APIs fall short

Every API passed the simple checks. Text inputs became text fields, the dropdown kept its five countries, checkboxes became checkboxes and the password field hid what you type. The failures in the matrix, 20 in total, fall into four groups, and the next four sections take them one at a time.

Missing input types

Nutrient only knows five input types, namely text, password, radio, checkbox and select. Everything else, our email, number and date inputs and both textareas, was printed as ordinary page content. That alone cost it several checks, and it took the pre-filled email and the page-two check down with it, since the only inputs on page two were a password and a textarea. jsreport has a different gap. Its field helper does text, dropdowns, checkboxes and signatures, but there is no radio type, so our plan options are simply not there. That is where all four of its misses come from. The other four services created every field in the form.

Field names get rewritten

If your code is going to read the filled form back, it is going to do that by field name, and only PDFGate and PDFCrowd gave us our names back exactly as we wrote them. DocRaptor renders with Prince, and Prince names fields after the form they sit in, so full_name comes back as Form1.full_name. Nutrient glues the id and the name together, and since our inputs use the same value for both, as most forms do, every name comes out doubled, like customer_id_customer_id. Where there is no id, it falls back to a hash. PDFMonkey will not accept email at all, because it is a reserved word in its marker syntax, and it will not accept underscores either. You can live with any of this if you know about it before you write the code that reads the values. You just need to know.

Lost defaults and pre-filled values

This is where PDFMonkey loses most of its points. Its markers can say what type a field is, how big it is and whether it is required, but they have no way of saying that the country is already France, the plan is already Pro, the terms box is already ticked or the email is already filled in. All four of those came back empty. PDFCrowd has a smaller version of the same problem, where both checkboxes arrived unticked. Nutrient lost the pre-filled email along with the field itself. Everyone else carried every default and every value across intact.

Required and read-only

Both required and readonly have a direct equivalent in a PDF form, and five of the six services set them. Nutrient dropped both. That matters more than it might seem. The required flag is what makes Acrobat and signing tools refuse a form with an empty field, and read-only is what stops a customer from quietly editing the ID you filled in for them.

Every output can be filled and flattened

Every single output passed the last check. We filled the fields with pdf-lib, saved the file, read the values back and flattened it, and all six PDFs behaved like proper AcroForm documents. So whichever service you end up with, the fields it makes are fields that other PDF software can use.

Speed and file size were not part of the score, but they are worth a look. jsreport was the fastest once it had warmed up, averaging 0.6 seconds after a 1.7-second first request. Nutrient came next at 1.1 seconds, then PDFGate at 1.6 (or 1.3 with fields turned off). DocRaptor and PDFCrowd took 2.2 and 2.7 seconds, and PDFMonkey averaged 7.2, with one request that took almost 13. On size, the Chrome-based services produce the largest files because they embed the page's web font, while DocRaptor and jsreport produced the two smallest at 36 and 33 KB.

Decide how you want fields made before you pick a service

Most of the differences above are not bugs. They follow directly from how each service gets from an HTML input to a PDF field, and across these six there are really only three ways of doing it.

Use the HTML you already have. PDFGate, PDFCrowd and Nutrient read the form itself. Your markup, your CSS and your names stay exactly as they are, and you switch fields on with one option in the request, enableFormFields for PDFGate and enable_pdf_forms for PDFCrowd, while Nutrient needs nothing at all. This is the least work by a long way, and it is the only approach that can keep everything the HTML says. In our test PDFGate did keep everything, PDFCrowd lost the ticked checkboxes, and Nutrient only understood some of the inputs.

Add one CSS rule. DocRaptor's Prince engine makes a field out of any input that carries -prince-pdf-form: enable, so a single line in your stylesheet covers the whole form. Prince kept every type, value and flag we gave it and produced very small files. The price you pay is that Form1. prefix on every field name.

Rewrite the form in markers. PDFMonkey and jsreport ignore your inputs altogether and build fields from their own syntax placed in the HTML. PDFMonkey wants a piece of text like [% data_form_field_text_fullname_w370_h25_required %]; jsreport wants a helper like {{{pdfFormField name='full_name' type='text' width='493px' height='33px'}}}. Because the browser no longer lays the field out, the size has to live in the marker too. For our form that meant rewriting 41 and 37 lines, anything the syntax cannot express has to be dropped or worked around, and from then on you are maintaining a second version of every form.

Have a look at the files

Every generated PDF is in the public test folder next to the source form, the runner and the check script, so you can open them in Acrobat and judge for yourself. The prices in the results table are in each provider's own currency, for monthly billing unless we say otherwise, and were checked in October 2026.

If you are looking at PDFGate in particular, the guide to fillable fields from HTML walks through every attribute the converter understands, and the HTML to PDF API page has the request format.

What we left out

Anvil can also create fields from ordinary inputs inside a <form>, but its terms of service do not allow benchmarking it against other products, so we respected that and left it out. Self-hosted libraries can do this too, among them wkhtmltopdf with --enable-forms and the .NET converters from EVO, HiQPdf and SelectPdf, but this test is about hosted APIs. As for the other hosted APIs we have tried (PDFShift, Browserless, Api2Pdf, ConvertAPI, CloudConvert, cloudlayer.io, APITemplate.io and PDF.co), they all print inputs as flat shapes. PDF.co suggests adding the fields afterwards with a separate forms API. How those APIs handle everything else on a page is covered in our rendering benchmark of 12 HTML to PDF APIs.

Try it with your own form

Our form is not your form, and no benchmark can promise what will happen to your document. Before you commit to a service, send it your real form with fields switched on, open the result in Acrobat and in whatever PDF library you use, and look at the names and values that come back. If you want to do it properly, the test form, runner and check script are all public. Drop in your HTML, describe its inputs in the script, and you get the same 17 checks on your own document.

Frequently asked questions

Which HTML to PDF APIs can create fillable PDF forms?

All six APIs we tested can, but not in the same way. PDFGate, PDFCrowd and Nutrient DWS work from the HTML inputs you already have. DocRaptor needs a Prince CSS rule on each input. PDFMonkey and jsreport want you to swap the inputs for their own markers or template helpers.

Which API kept the most of the HTML form?

PDFGate passed all 17 checks, so every type, name, default, pre-filled value and flag in our form came through unchanged. PDFCrowd and DocRaptor passed 16. PDFCrowd lost the ticked state of the checkboxes, and DocRaptor adds a Form1. prefix to every field name. jsreport scored 13, PDFMonkey 12 and Nutrient 8.

The results come from runs on 17 and 18 October 2026, using each API's documented options. If something looks wrong, open an issue in the repository and we will rerun it. Prices are from each provider's pricing page as of October 2026.

This website uses cookies to offer a better browsing experience. By clicking on the "Accept" button you accept our Cookie policy.