DEV Community

IronSoftware
IronSoftware

Posted on

Common HTML to PDF Problems in C#

Converting HTML to PDF in C# seems straightforward until you hit the inevitable issues: CSS doesn't render, images disappear, fonts look wrong, or the PDF is just blank.

I've debugged these problems hundreds of times. Here are the most common HTML-to-PDF issues and exactly how to fix them.

Why Is My CSS Not Rendering in the PDF?

This is the #1 problem developers encounter. Your HTML looks perfect in a browser, but the PDF ignores all styling.

Root cause: The PDF library can't find your CSS file because it's using a relative path.

Fix: Set a base URL so the library knows where to resolve relative paths:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<link rel='stylesheet' href='styles.css'>
<h1>Styled Content</h1>";

var renderer = new [ChromePdfRenderer](https://ironpdf.com/blog/videos/how-to-render-html-string-to-pdf-in-csharp-ironpdf/)();
renderer.RenderingOptions.BaseUrl = new Uri("https://example.com/");
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("styled.pdf");
Enter fullscreen mode Exit fullscreen mode

With BaseUrl set, styles.css resolves to https://example.com/styles.css.

Why Doesn't Inline CSS Work Either?

If even inline styles don't render, you're likely using a library that doesn't support modern CSS. This happens with older libraries like iTextSharp or wkhtmltopdf.

The problem:

// Using an older library that doesn't support CSS3
var html = "<div style='display: flex;'>Flexbox won't work</div>";
var pdf = oldLibrary.Convert(html); // Flexbox ignored
Enter fullscreen mode Exit fullscreen mode

Fix: Use a Chromium-based library like IronPDF that supports modern CSS:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<div style='display: flex; justify-content: space-between;'>
    <div>Left</div>
    <div>Right</div>
</div>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("flexbox.pdf");
Enter fullscreen mode Exit fullscreen mode

IronPDF uses Chromium, so CSS3 features (flexbox, grid, custom properties) all work.

Why Are My Images Missing from the PDF?

Images fail to load for two reasons: incorrect paths or blocked external requests.

Problem 1: Relative image paths

var html = "<img src='logo.png'>";
var pdf = renderer.RenderHtmlAsPdf(html); // Image missing!
Enter fullscreen mode Exit fullscreen mode

Fix: Use absolute URLs or set a base URL:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = "<img src='logo.png'>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.BaseUrl = new Uri("https://example.com/images/");
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("with-image.pdf");
Enter fullscreen mode Exit fullscreen mode

Now logo.png resolves to https://example.com/images/logo.png.

Problem 2: Local file paths don't work

// This won't work
var html = "<img src='C:\\images\\logo.png'>";
Enter fullscreen mode Exit fullscreen mode

Fix: Use file:/// protocol or convert images to base64:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

// Option 1: file:/// protocol
var html = "<img src='file:///C:/images/logo.png'>";

// Option 2: Base64 (better for portability)
var imageBytes = File.ReadAllBytes("logo.png");
var base64 = Convert.ToBase64String(imageBytes);
var html2 = $"<img src='data:image/png;base64,{base64}'>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html2);
pdf.SaveAs("embedded-image.pdf");
Enter fullscreen mode Exit fullscreen mode

Base64 embedding ensures images are always available, even if files move or get deleted.

Why Are Web Fonts Not Rendering Correctly?

If you're using Google Fonts or custom web fonts and they don't appear in the PDF, the library either can't fetch them or doesn't support @font-face.

Problem:

var html = @"
<link href='https://fonts.googleapis.com/css2?family=Roboto' rel='stylesheet'>
<div style='font-family: Roboto;'>This should be Roboto</div>";

var pdf = renderer.RenderHtmlAsPdf(html); // Falls back to default font
Enter fullscreen mode Exit fullscreen mode

Fix: IronPDF supports web fonts, but you may need to add a delay to ensure fonts load before rendering:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<link href='https://fonts.googleapis.com/css2?family=Roboto' rel='stylesheet'>
<div style='font-family: Roboto;'>Roboto font</div>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.RenderDelay = 500; // Wait 500ms for fonts to load
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("web-fonts.pdf");
Enter fullscreen mode Exit fullscreen mode

Alternatively, embed fonts directly with @font-face and base64:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<style>
    @font-face {
        font-family: 'CustomFont';
        src: url(data:font/woff2;base64,<BASE64_ENCODED_FONT>) format('woff2');
    }
    body { font-family: 'CustomFont'; }
</style>
<div>Custom embedded font</div>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("embedded-font.pdf");
Enter fullscreen mode Exit fullscreen mode

Why Is JavaScript Not Executing Before PDF Rendering?

If your HTML relies on JavaScript to populate content and the PDF is empty or incomplete, the library is rendering before JavaScript finishes executing.

Problem:

var html = @"
<div id='content'></div>
<script>
    setTimeout(() => {
        document.getElementById('content').innerText = 'Loaded!';
    }, 100);
</script>";

var pdf = renderer.RenderHtmlAsPdf(html); // Content missing!
Enter fullscreen mode Exit fullscreen mode

Fix: Add a render delay:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<div id='content'></div>
<script>
    setTimeout(() => {
        document.getElementById('content').innerText = 'Loaded!';
    }, 100);
</script>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.RenderDelay = 200; // Wait for JavaScript
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("javascript-rendered.pdf");
Enter fullscreen mode Exit fullscreen mode

For complex JavaScript apps (React, Vue, Angular), increase the delay or use WaitFor:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<div id='app'>Loading...</div>
<script>
    // Simulate React rendering
    setTimeout(() => {
        document.getElementById('app').innerHTML = '<h1>React App Loaded</h1>';
        window.renderedFlag = true;
    }, 500);
</script>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.WaitFor.RenderDelay(1000);
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("spa-rendered.pdf");
Enter fullscreen mode Exit fullscreen mode

Why Do Page Breaks Happen in the Wrong Places?

CSS page-break properties don't always work as expected, especially if you're using a library that doesn't support them.

Problem:

var html = @"
<div>Page 1</div>
<div style='page-break-after: always;'></div>
<div>Page 2</div>";

var pdf = oldLibrary.Convert(html); // Breaks at wrong places
Enter fullscreen mode Exit fullscreen mode

Fix: Use IronPDF, which respects CSS page break properties:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<div>Page 1 content</div>
<div style='page-break-after: always;'></div>
<div>Page 2 content</div>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("controlled-breaks.pdf");
Enter fullscreen mode Exit fullscreen mode

For finer control, use CSS page-break-inside: avoid; to prevent elements from splitting across pages:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<style>
    .keep-together { page-break-inside: avoid; }
</style>
<div class='keep-together'>
    <h2>Section Title</h2>
    <p>This entire section stays on one page.</p>
</div>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("no-split.pdf");
Enter fullscreen mode Exit fullscreen mode

Why Is the PDF Blank?

A completely blank PDF usually means an exception occurred during rendering but was silently swallowed.

Fix: Wrap rendering in try-catch and log exceptions:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

try
{
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf("<h1>Test</h1>");
    pdf.SaveAs("output.pdf");
}
catch (Exception ex)
{
    Console.WriteLine($"PDF generation failed: {ex.Message}");
    Console.WriteLine(ex.StackTrace);
}
Enter fullscreen mode Exit fullscreen mode

Common causes of blank PDFs:

  1. Invalid HTML: Unclosed tags, malformed markup
  2. Missing base URL: CSS/images can't load, library gives up
  3. JavaScript error: Unhandled JS exception stops rendering
  4. Licensing issue: Trial expired or license key invalid

Why Is the PDF Rendering Slowly?

If PDF generation takes 10+ seconds for simple documents, you're likely re-initializing the rendering engine.

Problem:

for (int i = 0; i < 100; i++)
{
    var renderer = new ChromePdfRenderer(); // Re-initializing each time!
    var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
    pdf.SaveAs($"doc-{i}.pdf");
}
Enter fullscreen mode Exit fullscreen mode

Fix: Reuse the renderer:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var renderer = new ChromePdfRenderer(); // Create once

for (int i = 0; i < 100; i++)
{
    var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
    pdf.SaveAs($"doc-{i}.pdf");
}
Enter fullscreen mode Exit fullscreen mode

First render: ~2.8 seconds (Chromium initialization).
Subsequent renders: <1 second.

This gives you a 5-20x speedup for batch operations.

Why Does PDF Generation Fail in Docker?

Docker containers often lack the native dependencies required for Chromium rendering.

Problem:

System.Exception: Failed to initialize Chromium rendering engine
Enter fullscreen mode Exit fullscreen mode

Fix: Install Chromium dependencies in your Dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:8.0

# Install Chromium dependencies for IronPDF
RUN apt-get update && apt-get install -y \
    libc6-dev \
    libgdiplus \
    libx11-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "YourApp.dll"]
Enter fullscreen mode Exit fullscreen mode

This installs the Linux packages IronPDF needs to run Chromium in a headless container.

Why Are Bootstrap/Tailwind Layouts Broken?

Older libraries (wkhtmltopdf, iTextSharp) use outdated rendering engines that don't support flexbox or CSS Grid. Bootstrap 4+ and Tailwind rely heavily on these features.

Problem:

var html = @"
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<div class='container'>
    <div class='row'>
        <div class='col'>Column 1</div>
        <div class='col'>Column 2</div>
    </div>
</div>";

var pdf = wkhtmltopdf.Convert(html); // Layout completely broken
Enter fullscreen mode Exit fullscreen mode

Fix: Use IronPDF with Chromium rendering:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var html = @"
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<div class='container'>
    <div class='row'>
        <div class='col'>Column 1</div>
        <div class='col'>Column 2</div>
    </div>
</div>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.RenderDelay = 300; // Wait for CSS to load
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("bootstrap-layout.pdf");
Enter fullscreen mode Exit fullscreen mode

Why Do Headers and Footers Overlap Content?

If you're setting custom headers/footers and they overlap page content, you need to adjust margins.

Problem:

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='height: 50px;'>Header</div>"
};

var pdf = renderer.RenderHtmlAsPdf("<h1>Content</h1>");
// Header overlaps content!
Enter fullscreen mode Exit fullscreen mode

Fix: Increase top margin to accommodate header height:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align: center;'>My Header</div>"
};

renderer.RenderingOptions.MarginTop = 60; // Make room for header
var pdf = renderer.RenderHtmlAsPdf("<h1>Content</h1>");
pdf.SaveAs("with-header.pdf");
Enter fullscreen mode Exit fullscreen mode

Same applies for footers—increase MarginBottom.

Why Is the PDF Pixelated or Low Quality?

If images or text look pixelated, you may be using a low DPI setting.

Fix: Increase DPI via rendering options:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.Dpi = 300; // High quality (default is 96)

var pdf = renderer.RenderHtmlAsPdf("<h1>High Quality PDF</h1>");
pdf.SaveAs("high-dpi.pdf");
Enter fullscreen mode Exit fullscreen mode

DPI values:

  • 96 (default): Standard screen quality
  • 150: Good for printing
  • 300: High quality for professional printing

Higher DPI increases file size, so balance quality vs. file size.

Why Does Multi-Threading Cause Crashes?

If you're rendering multiple PDFs in parallel and the application crashes, you're likely exceeding available memory or hitting thread-safety issues.

Fix: Limit parallelism:

using IronPdf;
using System.Threading.Tasks.Dataflow;
// Install via NuGet: Install-Package IronPdf

var renderer = new ChromePdfRenderer();

var options = new ExecutionDataflowBlockOptions
{
    MaxDegreeOfParallelism = 4 // Limit concurrent renders
};

var block = new ActionBlock<string>(async html =>
{
    var pdf = await renderer.RenderHtmlAsPdfAsync(html);
    await pdf.SaveAsAsync($"{Guid.NewGuid()}.pdf");
}, options);

foreach (var html in htmlDocuments)
{
    await block.SendAsync(html);
}

block.Complete();
await block.Completion;
Enter fullscreen mode Exit fullscreen mode

This prevents memory exhaustion by controlling how many PDFs render simultaneously.

How Do I Debug "License Key Required" Errors?

If you see license errors in production but not in development:

Problem:

IronPdf.Exceptions.LicensingException: License key required
Enter fullscreen mode Exit fullscreen mode

Fix: Ensure the license key is set before rendering:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Licensed PDF</h1>");
pdf.SaveAs("output.pdf");
Enter fullscreen mode Exit fullscreen mode

Store the license key in environment variables or app settings, never hardcode it:

IronPdf.License.LicenseKey = Environment.GetEnvironmentVariable("IRONPDF_LICENSE");
Enter fullscreen mode Exit fullscreen mode

Quick Troubleshooting Checklist

When HTML-to-PDF conversion fails, check these in order:

  1. Is the HTML valid? Test in a browser first
  2. Are paths absolute? Use full URLs or set BaseUrl
  3. Is JavaScript enabled? Add RenderDelay if needed
  4. Are fonts loading? Embed fonts or add delay
  5. Is the library modern? Avoid wkhtmltopdf/iTextSharp for HTML conversion
  6. Are Docker dependencies installed? Install libgdiplus, libx11-dev
  7. Is the license valid? Check expiration and deployment scope
  8. Is memory sufficient? Limit parallelism for batch operations

Most HTML-to-PDF issues trace back to path resolution or using an outdated library. Use IronPDF with Chromium rendering, set BaseUrl, and 90% of problems disappear.


Written by Jacob Mellor, CTO at Iron Software. Jacob created IronPDF and leads a team of 50+ engineers building .NET document processing libraries.

Top comments (0)