§HOW-TO GUIDE · C# · .NET 8 & 10

HTML to PDF in C#: convert a URL or an HTML string

Create an HtmlToPdf converter, set the page size and margins, then call ConvertUrl for a web page or ConvertHtmlString for HTML you build yourself. The same code runs on Windows, Linux and macOS.

Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64

Video walkthrough · 3:02 · Watch on YouTube · Short · 1:03
§STEP BY STEP

Build it step by step.

  1. 1Install the NuGet packages

    SelectPdf.Universal is the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.

    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.win-x64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.linux-x64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.linux-arm64
    terminal
    dotnet add package SelectPdf.Universal
    dotnet add package SelectPdf.Universal.Native.osx-arm64
  2. 2Create a console app

    Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace Program.cs with the code below.

    terminal
    dotnet new console -n PdfSample
    cd PdfSample
  3. 3Create the converter

    Program.cs · lines 1–3
    using SelectPdf.Universal;
    
    HtmlToPdf converter = new HtmlToPdf();

    HtmlToPdf is the converter. One object can convert several pages, one after another.

  4. 4Set A4 and 20 mm margins

    Program.cs · lines 5–11
    // A4 portrait with 20 mm margins (margins are in points: 20 mm = 57 pt)
    converter.Options.PdfPageSize = PdfPageSize.A4;
    converter.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
    converter.Options.MarginTop = 57;
    converter.Options.MarginBottom = 57;
    converter.Options.MarginLeft = 57;
    converter.Options.MarginRight = 57;

    PdfPageSize and PdfPageOrientation set the paper. Margins are in points (1/72 inch): 20 mm is 57 points. The defaults are A4 portrait with no margins, so set what your document needs.

  5. 5Convert a web page by URL

    Program.cs · lines 13–16
    // 1. a web page, by URL
    PdfDocument page = converter.ConvertUrl("https://selectpdf.com");
    page.Save("webpage.pdf");
    page.Close();

    ConvertUrl loads the page in the Chromium engine, runs its scripts and styles, and returns a PdfDocument. Save writes it and Close releases it.

  6. 6Convert an HTML string

    Program.cs · lines 18–26
    // 2. an HTML string; the base URL resolves relative images, styles and links
    string html = """
        <img src="img/selectpdf-logo-h128.png" alt="SelectPdf" height="40">
        <h1>Invoice #1042</h1>
        <p>Issued to Contoso Ltd on 12 October 2026.</p>
        """;
    PdfDocument invoice = converter.ConvertHtmlString(html, "https://selectpdf.com/");
    invoice.Save("invoice.pdf");
    invoice.Close();

    ConvertHtmlString takes HTML you build yourself, such as a template filled with your data. The second argument is the base URL: the relative image path img/selectpdf-logo-h128.png is loaded from https://selectpdf.com/. Without external references, the one-argument overload is enough.

  7. 7Run it

    terminal
    dotnet run

    The program writes webpage.pdf to the working folder. Without a license key, every page carries a trial watermark; set GlobalProperties.LicenseKey before the first conversion to remove it.

§COMPLETE PROGRAM

The complete Program.cs.

This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.

Program.cs
using SelectPdf.Universal;

HtmlToPdf converter = new HtmlToPdf();

// A4 portrait with 20 mm margins (margins are in points: 20 mm = 57 pt)
converter.Options.PdfPageSize = PdfPageSize.A4;
converter.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
converter.Options.MarginTop = 57;
converter.Options.MarginBottom = 57;
converter.Options.MarginLeft = 57;
converter.Options.MarginRight = 57;

// 1. a web page, by URL
PdfDocument page = converter.ConvertUrl("https://selectpdf.com");
page.Save("webpage.pdf");
page.Close();

// 2. an HTML string; the base URL resolves relative images, styles and links
string html = """
    <img src="img/selectpdf-logo-h128.png" alt="SelectPdf" height="40">
    <h1>Invoice #1042</h1>
    <p>Issued to Contoso Ltd on 12 October 2026.</p>
    """;
PdfDocument invoice = converter.ConvertHtmlString(html, "https://selectpdf.com/");
invoice.Save("invoice.pdf");
invoice.Close();

Open the project on GitHub → this program and the variations below, ready to dotnet run

§OUTPUT

The PDF it produces.

First page of webpage.pdf, the PDF this sample produces
webpage.pdf, page 1

Download webpage.pdf ↓ the file this sample produced, unedited

§VARIATIONS

Variations you will need next.

Each variation is a separate file in the same project, compiled and run with the program above.

Use the page's print stylesheet

Many sites hide navigation and ads in @media print rules. CssMediaType = HtmlToPdfCssMediaType.Print applies them, as the browser's Print command does.

PrintStylesheet.cs
using SelectPdf.Universal;

static class PrintStylesheet
{
    public static void Run()
    {
        HtmlToPdf converter = new HtmlToPdf();
        converter.Options.PdfPageSize = PdfPageSize.A4;

        // use the page's @media print rules, as the browser's Print command does
        converter.Options.CssMediaType = HtmlToPdfCssMediaType.Print;

        PdfDocument doc = converter.ConvertUrl("https://selectpdf.com");
        doc.Save("webpage-print.pdf");
        doc.Close();
    }
}

Wait for content that JavaScript adds

Charts and data grids often appear after the page has loaded. ConversionDelay waits a number of seconds before rendering, and NavigationTimeout fails a page that never finishes loading instead of waiting forever.

WaitForJavaScript.cs
using SelectPdf.Universal;

static class WaitForJavaScript
{
    public static void Run()
    {
        // content that a script adds half a second after the page loads, like a chart or a data grid
        string html = """
            <h1>Sales report</h1>
            <div id="chart">loading...</div>
            <script>
              setTimeout(() => document.getElementById("chart").textContent = "Q3 revenue: 1.2M", 500);
            </script>
            """;

        HtmlToPdf converter = new HtmlToPdf();
        converter.Options.ConversionDelay = 2;      // seconds to wait after the page loads
        converter.Options.NavigationTimeout = 30;   // seconds before a page that never loads fails

        PdfDocument doc = converter.ConvertHtmlString(html);
        doc.Save("report.pdf");
        doc.Close();
    }
}

Convert asynchronously, with a timeout

In a web app or a service, ConvertUrlAsync and ConvertHtmlStringAsync hold no thread while the page loads. A CancellationToken stops a conversion that takes too long. Save() without a file name returns the PDF as bytes.

ConvertAsync.cs
using SelectPdf.Universal;

static class ConvertAsync
{
    public static async Task Run()
    {
        // in a web app or service: await the conversion, and give up after 30 seconds
        using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(30));

        HtmlToPdf converter = new HtmlToPdf();
        PdfDocument doc = await converter.ConvertUrlAsync("https://selectpdf.com", timeout.Token);

        byte[] pdf = doc.Save();   // the PDF as bytes, for a response or a database
        doc.Close();

        await File.WriteAllBytesAsync("webpage-async.pdf", pdf);
    }
}
§TROUBLESHOOTING

Common problems and fixes.

Images or styles are missing from an HTML string

Relative paths need a base URL: pass it as the second argument of ConvertHtmlString, or use absolute URLs in the HTML.

The page looks smaller than in the browser

The converter lays the page out as a 1024 pixel wide browser window and scales it to the PDF page. Set Options.WebPageWidth to change that width: a smaller width makes the content larger.

Part of the page is missing

Content that scripts add after the page loads needs Options.ConversionDelay. Content behind a login needs the cookies or headers of a signed-in user: see the authentication topics in the documentation.

§GOOD TO KNOW

Good to know.

  • Margins are set in points: 1 point is 1/72 inch, so 20 mm is 57 points. Source
  • With a base URL, ConvertHtmlString resolves relative images, style sheets and links against it. Source
  • ConversionDelay waits after the page loads, for content that scripts add; NavigationTimeout limits the wait for a slow page. Source
  • The converter renders with the screen CSS media type by default; Print applies the page's print styles. Source
?FAQ

Questions, answered.

Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.

Create an HtmlToPdf converter and call ConvertUrl with the address. It returns a PdfDocument: call Save with a file name, or Save() for the bytes, then Close.
Set converter.Options.PdfPageSize to PdfPageSize.A4 and the four margin options to 57: margins are in points, and 20 mm is 57 points.
Yes. SelectPdf.Universal targets .NET 8 and .NET 10 and runs on Windows, Linux x64 and ARM64, and macOS on Apple Silicon. Reference the native package for your platform, for example SelectPdf.Universal.Native.linux-x64.
The Community Edition converts HTML to PDF for free, up to 5 pages per document. The commercial library has a free trial with no limits, which adds a watermark until you set a license key.