Rendering
Every render starts from a CobaltEngine instance and ends with one of the three terminal methods. Options set before the terminal call are consumed and reset automatically, so the same CobaltEngine instance is safe to reuse.
Render from a URL
var renderer = new CobaltEngine();
var pdf = await renderer.RenderUrlAsPdfAsync("https://example.com");
pdf.SaveAs("output.pdf");
Chromium navigates to the URL, waits for the page to be ready (configurable via Wait Strategies), and captures the PDF.
Render from an HTML String
string html = """
<html>
<head>
<style>body { font-family: sans-serif; padding: 40px; }</style>
</head>
<body>
<h1>Invoice #1042</h1>
<p>Total due: <strong>£149.99</strong></p>
</body>
</html>
""";
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
// Access raw bytes directly — no file is written
byte[] bytes = pdf.BinaryData;
// Stream it to a client, upload to S3, attach to an email, etc.
Note
The HTML is loaded into Chromium using page.setContent(). External resources (images, fonts, scripts) referenced by absolute URLs are fetched normally. Relative URLs will not resolve — use absolute URLs or embed resources inline (e.g. Base64 images, inline CSS).
Render from an HTML File
var pdf = await renderer.RenderHtmlFileAsPdfAsync("C:/reports/invoice.html");
pdf.SaveAs("invoice.pdf");
The file is read from disk and rendered as an HTML string. The same note about relative URLs applies.
Saving the Output
PdfDocument exposes three ways to persist or consume the result:
// Classic two-step
var pdf = await renderer.RenderUrlAsPdfAsync("https://example.com");
pdf.SaveAs("output.pdf");
// Chain SaveAs directly off the render call — no intermediate variable needed
await renderer
.Landscape()
.RenderUrlAsPdfAsync("https://example.com")
.SaveAs("output_landscape.pdf");
// Async variant — uses File.WriteAllBytesAsync internally
await renderer
.RenderUrlAsPdfAsync("https://example.com")
.SaveAsAsync("output.pdf");
// Get raw bytes (for streaming, email, blob storage, etc.)
var pdf = await renderer.RenderUrlAsPdfAsync("https://example.com");
byte[] bytes = pdf.BinaryData;
// Get a Stream
using var stream = pdf.GetStream();
await stream.CopyToAsync(responseStream);
SaveAs vs SaveAsAsync
Both methods are available both on PdfDocument directly and as extension methods on Task<PdfDocument>, so they can be chained straight off any render call.
| Method | Where callable | Write | Returns |
|---|---|---|---|
SaveAs(path) |
PdfDocument or Task<PdfDocument> |
Synchronous | PdfDocument |
SaveAsAsync(path) |
PdfDocument or Task<PdfDocument> |
Async (File.WriteAllBytesAsync) |
Task<PdfDocument> |
Paper Format and Orientation
var pdf = await renderer
.WithPaperFormat("A3") // change paper size
.Landscape() // landscape orientation
.RenderUrlAsPdfAsync("https://example.com");
The paper format defaults to A4. Use WithPaperFormat to change it:
| Format string | Dimensions |
|---|---|
"A4" (default) |
210 × 297 mm |
"A3" |
297 × 420 mm |
"Letter" |
8.5 × 11 in |
"Legal" |
8.5 × 14 in |
"Tabloid" |
11 × 17 in |
Margins
Margins default to 1 cm on all sides. Use WithMargins to change them:
using CobaltPdf.Configuration;
using CobaltPdf.Enums;
// No margins at all
var pdf = await renderer
.WithMargins(MarginOptions.None)
.RenderUrlAsPdfAsync("https://example.com");
// Uniform margin
var pdf2 = await renderer
.WithMargins(new MarginOptions(15, MarginUnit.Millimeters))
.RenderUrlAsPdfAsync("https://example.com");
// Different top/bottom and left/right
var pdf3 = await renderer
.WithMargins(new MarginOptions(topBottom: 10, leftRight: 20, MarginUnit.Millimeters))
.RenderUrlAsPdfAsync("https://example.com");
// Full per-side control
var pdf4 = await renderer
.WithMargins(new MarginOptions(top: 10, right: 15, bottom: 10, left: 15, MarginUnit.Millimeters))
.RenderUrlAsPdfAsync("https://example.com");
Tip
Headers and footers are rendered inside the margin area. If your header or footer is clipped, increase the top or bottom margin respectively.
Print Media
To render using the page's @media print CSS rules instead of @media screen:
using CobaltPdf.Enums;
var pdf = await renderer
.EmulateMediaType(CssMediaType.Print)
.RenderUrlAsPdfAsync("https://example.com");
Grayscale
var pdf = await renderer
.UseGrayscale()
.RenderUrlAsPdfAsync("https://example.com");
CSP Bypass
Some pages use a strict Content Security Policy that would block injected fonts or custom scripts. Enable the bypass flag when needed:
var pdf = await renderer
.WithCspBypass()
.ConfigureFonts("C:/fonts")
.RenderUrlAsPdfAsync("https://strict-csp-site.com");
Cancellation
All three render methods accept an optional CancellationToken. Cancelling aborts the pool lease acquire, or the in-progress render if it has already started.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var pdf = await renderer
.RenderUrlAsPdfAsync("https://example.com", cts.Token);
In ASP.NET Core, pass HttpContext.RequestAborted to automatically cancel if the HTTP client disconnects:
[HttpGet("report")]
public async Task<IActionResult> GetReport(CancellationToken cancellationToken)
{
var pdf = await _renderer
.WithPaperFormat("A4")
.RenderUrlAsPdfAsync("https://example.com/report", cancellationToken);
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
Parallel Renders
CobaltEngine is thread-safe. Multiple concurrent renders on the same instance each get their own browser lease from the pool:
var renderer = new CobaltEngine();
var tasks = Enumerable.Range(1, 10).Select(i =>
renderer.RenderUrlAsPdfAsync("https://example.com"));
var results = await Task.WhenAll(tasks);
Console.WriteLine($"Rendered {results.Length} PDFs");