How to Convert HTML to PDF with SelectPdf in C#
Convert a URL or HTML string to PDF in C# with SelectPdf, including assets, engines, deployment limits, errors, and a ScreenshotNeo alternative.
Direct answer: SelectPdf uses the HtmlToPdf class. Call ConvertUrl when the source is a web address, or ConvertHtmlString when you already have HTML. Save the returned PdfDocument, then close it to release conversion resources.
using SelectPdf;
var converter = new HtmlToPdf();
var document = converter.ConvertUrl("https://www.example.com");
document.Save("output.pdf");
document.Close();
For markup containing relative images, stylesheets, or fonts, pass a base URL:
using SelectPdf;
var html = "<html><body><img src=\"images/logo.png\"></body></html>";
var baseUrl = "https://www.example.com/";
var converter = new HtmlToPdf();
var document = converter.ConvertHtmlString(html, baseUrl);
document.Save("output.pdf");
document.Close();
1. Install the correct SelectPdf package
SelectPdf is distributed through NuGet. The vendor lists Select.HtmlToPdf.NetCore for modern .NET targets, including .NET 5 through .NET 10 and supported .NET Core/.NET Standard targets. The legacy Select.HtmlToPdf package is for older .NET Framework applications. Check the current SelectPdf installation documentation for the exact version and target you use.
dotnet add package Select.HtmlToPdf.NetCore
The official .NET Core package guidance is Windows-specific. The package does not run on Linux or macOS according to the vendor documentation, so confirm the operating system before choosing your deployment architecture. Install one main package. If you select Blink or Chromium, install the matching companion package described by the same installation instructions.
2. Convert a public URL
ConvertUrl lets SelectPdf load and render a web page, including its referenced resources.
using SelectPdf;
public static void ConvertUrlToPdf(string url, string outputPath)
{
var converter = new HtmlToPdf();
PdfDocument? document = null;
try
{
document = converter.ConvertUrl(url);
document.Save(outputPath);
}
finally
{
document?.Close();
}
}
ConvertUrlToPdf("https://www.example.com", "example.pdf");
Use a fully qualified HTTPS URL when possible. The target must be reachable from the machine running the conversion. Private localhost addresses, VPN-only pages, authentication walls, robots or network policies can prevent loading even when the page works in your desktop browser.
3. Convert an HTML string
Use ConvertHtmlString when your application generates the markup itself.
using SelectPdf;
public static void ConvertHtmlToPdf(string html, string outputPath)
{
var converter = new HtmlToPdf();
PdfDocument? document = null;
try
{
document = converter.ConvertHtmlString(html);
document.Save(outputPath);
}
finally
{
document?.Close();
}
}
var html = """
Invoice
Generated from an HTML string.
""";
ConvertHtmlToPdf(html, "invoice.pdf");
If the HTML uses relative paths such as css/site.css or images/logo.png, provide a base URL:
var converter = new HtmlToPdf();
var document = converter.ConvertHtmlString(html, "https://static.example.com/app/");
try
{
document.Save("output.pdf");
}
finally
{
document.Close();
}
The base URL is only a resolver for relative references; it does not upload local files. For local assets, use paths and access rules supported by your selected engine and deployment environment, or make the assets available from a reachable origin.
4. Configure page output and rendering
SelectPdf documents four rendering engines: WebKit, WebKit Restricted, Blink, and Chromium. WebKit is the default and is intended for ES5 JavaScript and classic CSS. Blink and Chromium target newer HTML, CSS, and JavaScript; Chromium is distributed through a separate companion package. Engine and package compatibility depends on your framework and version, so verify the current engine documentation before deployment.
Choose the engine based on the source page:
| Requirement | What to check |
|---|---|
| Modern JavaScript | Whether the selected engine supports the syntax and APIs used by the page. |
| Modern CSS | Grid, flexbox, custom properties, print rules, and web fonts in representative pages. |
| Deployment platform | Framework, Windows version, native dependencies, and companion package requirements. |
| Pagination | Page breaks, repeating headers, tables, images, margins, and font embedding. |
Page size, orientation, margins, headers, footers, and other PDF settings are exposed through the converter options documented for your package version. Set them before conversion, then render representative documents in the actual deployment environment. Do not assume that a page that looks correct in a desktop browser will paginate identically in a PDF engine.
5. Return a PDF from ASP.NET Core
The returned PdfDocument can be saved to a file, stream, memory buffer, or HTTP response. A minimal controller can write the document to a memory stream:
using Microsoft.AspNetCore.Mvc;
using SelectPdf;
[ApiController]
[Route("pdf")]
public sealed class PdfController : ControllerBase
{
[HttpPost]
public IActionResult Create([FromBody] string html)
{
var converter = new HtmlToPdf();
var document = converter.ConvertHtmlString(html);
try
{
using var stream = new MemoryStream();
document.Save(stream);
return File(stream.ToArray(), "application/pdf", "document.pdf");
}
finally
{
document.Close();
}
}
}
Validate or sanitize untrusted HTML before rendering. Treat external URLs, scripts, cookies, and custom headers as input that can affect network access and resource usage.
6. Community Edition, trial, and commercial licensing
The vendor describes the Community Edition as free for personal and commercial use, without a watermark, with a limit of five pages per generated PDF. It is different from the commercial-library trial, which exposes the full feature set but watermarks every page. The commercial library removes those limits under its license. Confirm the current page limit and licensing terms on the official product pages before shipping.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Images or CSS are missing | Relative URLs have no base URL, or resources cannot be reached. | Pass baseUrl to ConvertHtmlString; verify URLs from the converter host. |
| Modern page renders incorrectly | The selected engine does not support the page’s JavaScript or CSS. | Evaluate Blink or Chromium and install its matching companion package. |
| Works locally, fails in production | Framework, Windows runtime, permissions, native dependencies, or network differences. | Use the same package and engine in a staging environment that matches production. |
| PDF is blank or incomplete | Resources timed out, scripts did not finish, or the URL requires authentication. | Check reachability, authentication handling, JavaScript requirements, and engine compatibility. |
| Document remains locked or memory grows | PdfDocument.Close() was not called on every path. |
Put Save and Close in a try/finally block. |
| Too many pages in Community Edition | The output exceeds the documented five-page limit. | Reduce the document or use a properly licensed commercial edition. |
| Trial output has a watermark | The commercial trial is being used. | Obtain the appropriate commercial license or use the Community Edition within its limits. |
8. Reliability, performance, and cost considerations
- Measure your own workload. The supplied research contains no independent speed, fidelity, or reliability benchmarks.
- Reuse application infrastructure carefully. Conversion is resource-intensive; control concurrency and monitor CPU, memory, temporary files, and conversion duration.
- Use deterministic assets. Pin CSS, fonts, images, and JavaScript versions when reproducible output matters.
- Handle failures explicitly. Set request-level timeouts around your application call, log the source URL and engine, and retry only failures that are safe to repeat.
- Budget licensing separately from hosting. Community Edition page limits, commercial licensing, and any engine companion requirements are distinct decisions.
9. Or skip the browser setup
If you need a clean screenshot or PDF from a URL without maintaining a rendering package, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and lets you turn each step off.
ScreenshotNeo bills only clean shots. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Plans include 1,000 free shots per month without a card; paid plans start at $5 for 3,000 shots.
See the ScreenshotNeo API documentation for all options.
C#
using System.Net.Http;
using var http = new HttpClient();
var url = "https://api.screenshotneo.com/v1/shot" +
"?access_key=YOUR_API_KEY" +
"&url=https%3A%2F%2Fstripe.com";
var bytes = await http.GetByteArrayAsync(url);
await File.WriteAllBytesAsync("shot.webp", bytes);
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', buffer);
Create a free ScreenshotNeo account for 1,000 screenshots each month with no card.
10. FAQ
Can SelectPdf convert an HTML string without hosting it?
Yes. Use ConvertHtmlString. Add a base URL when the markup references relative assets.
Do I need to close the PDF document?
Yes. Save first, then call Close(), preferably from a finally block.
Can the .NET Core package run on Linux?
The current vendor guidance says the .NET Core package is Windows-specific. Verify the version documentation before deployment.
Which engine should I choose?
Start with WebKit for ES5-era pages. Consider Blink or Chromium for modern JavaScript and CSS, then validate output on your target host.
Does the Community Edition have a page limit?
The vendor describes a five-page limit per generated PDF. Confirm current terms before relying on it.


