EvoPdf alternative: a hosted HTML to PDF API for .NET
EvoPdf (EVO HTML to PDF Converter) is a commercial HTML-to-PDF library for .NET and C#. It ships as NuGet packages, runs inside your own application process, and is sold under perpetual licenses. pdfkitt takes the other approach: a hosted API backed by current Chromium, so your .NET app makes one HttpClient call and never hosts, updates, or licenses a rendering engine. This page compares the two models honestly and shows the C# migration.
Updated November 2026.
EvoPdf vs pdfkitt: feature comparison
The two products solve the same problem with opposite architectures. EvoPdf is a library that lives in your process; pdfkitt is a service that lives behind an HTTPS endpoint. Most of the practical differences follow from that one choice.
| EvoPdf | pdfkitt API | |
|---|---|---|
| Deployment model | Library that runs in-process inside your .NET application | Hosted API: your app sends HTML over HTTPS and receives PDF bytes |
| Installation | NuGet packages (EvoPdf.HtmlToPdf) added to each project that renders | Nothing to install; a plain HttpClient call from any .NET project |
| Rendering engine | Bundled with the library; you update it by updating the package | Current Chromium via Playwright, maintained on the pdfkitt side |
| Licensing | Commercial perpetual licenses (two license types listed on its site) | Free tier of 1,000 PDFs/month, then per-document plans from $19/month |
| Language support | .NET and C# | Any language with an HTTP client, including C#/.NET, Node.js, Python, PHP, Java, Go |
| Where your HTML goes | Stays inside your own process | Sent to pdfkitt over HTTPS, processed in memory, never stored |
Why teams look for an EvoPdf alternative
Teams rarely leave EvoPdf because it stopped working. They leave because the in-process model carries ongoing responsibilities that a hosted API removes:
- You own the engine lifecycle. When the library moves between generations, such as EvoPdf Classic and EvoPdf Next, you evaluate, update the NuGet package, retest your templates, and redeploy every service that renders.
- Rendering competes with your app for resources. HTML-to-PDF conversion is CPU- and memory-heavy. Running it inside an ASP.NET Core request pipeline means PDF spikes show up as latency on unrelated endpoints, and scaling the renderer means scaling the whole app.
- Licensing is tied to deployment shape. A perpetual license is a good fit for a fixed set of servers. It fits less well with autoscaling containers, serverless functions, and microservices where several codebases need to produce PDFs.
- Polyglot teams need one renderer. If a Node.js service and a Python job also generate documents, a .NET-only library forces either duplicate tooling or a .NET sidecar. An HTTP API gives every language the same output.
- Non-Latin text has to look right. Shipping and verifying fonts for Arabic, CJK, and right-to-left documents on every host is easy to get wrong. pdfkitt renders with Noto fonts on its side, so those scripts work without font installation in your container.
None of these are flaws in EvoPdf. They are the cost of in-process rendering, and for some teams that cost is worth paying. The next sections help you decide which side you are on.
How to migrate from EvoPdf to pdfkitt
Your HTML generation does not change. Whatever produces the markup today, a Razor view rendered to a string, a template engine, or a plain StringBuilder, keeps doing that. The only part that moves is the final conversion step.
// Before: EvoPdf runs inside your .NET process.
// Exact API depends on the EvoPdf generation you use.
using EvoPdf;
var converter = new HtmlToPdfConverter();
converter.LicenseKey = licenseKey;
byte[] pdf = converter.ConvertHtml(html, baseUrl);
await File.WriteAllBytesAsync("invoice.pdf", pdf);Replace the converter with a POST to https://api.pdfkitt.dev/v1/convert. Send a Bearer API key, a JSON body with exactly one of html or url, and optional page options. A 200 response is the PDF itself.
// After: one HttpClient call to pdfkitt. No NuGet package.
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer",
Environment.GetEnvironmentVariable("PDFKITT_API_KEY"));
var response = await http.PostAsJsonAsync(
"https://api.pdfkitt.dev/v1/convert",
new
{
html,
options = new
{
page_size = "A4",
margins = new { top = "20mm", bottom = "20mm", left = "15mm", right = "15mm" },
print_background = true,
},
});
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync("invoice.pdf",
await response.Content.ReadAsByteArrayAsync());The options object accepts page_size (A4, Letter, or Legal), margins as an object of CSS lengths (top, right, bottom, left), landscape, and print_background. Map whichever converter properties you set in EvoPdf onto these fields; most invoice and report templates only need page size and margins. Non-200 responses are JSON, which makes error handling straightforward:
// Errors come back as JSON instead of a 200 with PDF bytes.
if (!response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
// { "error": { "code": "...", "message": "...",
// "request_id": "...", "docs_url": "..." } }
throw new InvalidOperationException(body);
}Because pdfkitt keeps a warm pool of Chromium instances, a typical conversion returns in well under a second, so the HTTP round trip does not add a noticeable wait compared with an in-process call. Then remove the EvoPdf package reference and the license key from configuration, and the .NET project no longer carries a rendering engine at all.
Quick start in curl, Node.js, and Python
The C# sample above is the same request every other language makes. If other services in your stack also need PDFs, these snippets from the pdfkitt dashboard are the whole integration. Swap in your API key, send HTML, and write the response to a file.
Try it now — run this in your terminal (30 seconds)
No setup needed. Just paste this command and you'll get a real PDF back.
curl https://api.pdfkitt.dev/v1/convert \
-H "Authorization: Bearer pdfk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Hello, world!</h1>"}' \
--output document.pdfWhen to stay on EvoPdf
An in-process library is the right tool in several situations, and switching would be a step backwards:
- Your HTML cannot leave the process. pdfkitt processes HTML in memory and never stores it, but it still travels over HTTPS to a third party. Air-gapped networks, strict data-residency rules, or contracts that forbid sending document content to any external service all rule out a hosted API.
- You render offline or on desktops. Desktop and on-premises .NET applications that must work without internet access need a local engine.
- You already own a perpetual license and the output is stable. If your templates render correctly, your volume is predictable, and nobody is spending time on engine upgrades, there is no urgent reason to migrate.
- You depend on library-level features. If your code uses capabilities that only make sense inside a .NET object model, confirm pdfkitt's options cover what you need before you move.
When to choose pdfkitt
A hosted API wins when the operational cost of rendering matters more than keeping the engine local:
- You deploy to containers, Linux, or serverless. There is nothing to install and no native dependency to match, so a Docker image or Azure Function that generates PDFs looks exactly like one that does not.
- You want browser-accurate CSS without owning a browser. pdfkitt renders with real, current Chromium through Playwright. Flexbox, Grid, web fonts, and print CSS behave as they do in Chrome, and updates happen on our side.
- More than one language generates documents. One endpoint, one set of options, identical output whether the caller is C#, Node.js, Python, or a shell script.
- You prefer usage-based cost. The free tier covers 1,000 PDFs a month with no credit card, and paid plans start at $19/month priced per document. Low-volume services pay little; busy ones pay for what they render.
- You ship multilingual documents. Noto fonts for Arabic, CJK, and RTL text are already present on the renderer, so invoices in Japanese or Arabic come out correctly without font work in your deployment.
If you are evaluating .NET options more broadly, the C# and .NET guide covers Razor views, Blazor components, and the other library and wrapper choices.
FAQ
Is pdfkitt a drop-in replacement for EvoPdf?
Not in the sense of a NuGet package with the same class names. EvoPdf is a library you call in-process; pdfkitt is an HTTP API you call with HttpClient. The migration is usually a few lines: build the HTML string the way you already do, POST it to https://api.pdfkitt.dev/v1/convert with a Bearer API key, and write the returned bytes to disk or a response stream.
Does pdfkitt work on Linux, Docker, and Azure App Service?
Yes. Because rendering happens on the pdfkitt side, there is no native dependency, browser download, or platform-specific package in your deployment. Any environment that can make an outbound HTTPS request works, including Linux containers, Windows hosts, Azure, AWS, and serverless functions.
Which rendering engine does pdfkitt use?
Real, current Chromium driven by Playwright. CSS Grid, Flexbox, web fonts, and print CSS render the way they do in a modern browser. pdfkitt keeps the engine updated, so your application never ships or upgrades a renderer.
Is there a free tier or community edition?
There is a free tier of 1,000 PDFs per month with no credit card required. It uses the same API, the same Chromium renderer, and the same options as paid plans, so you can migrate a real workload before deciding whether to pay.
How is pdfkitt licensed compared with a perpetual license?
pdfkitt does not sell licenses at all. You pay per document on a monthly plan, starting at $19/month above the free tier, and you can stop at any time. There are no per-developer or per-server seats and no upgrade fees for new engine versions because the engine is hosted.
Does pdfkitt execute JavaScript in my HTML?
Not by default. Static HTML and CSS render as-is. If your template needs scripts to run, for example client-rendered charts, set javascript: true in the request. The page then runs in sandboxed Chromium with a 30-second cap before the PDF is captured.
Try pdfkitt free - 1,000 PDFs/month, no credit card
Get an API key and replace your first EvoPdf conversion with one HttpClient call.