Advanced PDF Generation
Headers & Footers
- C# / .NET
- Node.js
var request = new PdfGenerateRequest
{
HtmlContent = htmlBody,
Options = new PdfOptions
{
Format = PdfPageFormat.A4,
DisplayHeaderFooter = true,
HeaderTemplate = @"
<div style='font-size:10px; width:100%; text-align:center;'>
<span>My Company - Confidential</span>
</div>",
FooterTemplate = @"
<div style='font-size:10px; width:100%; text-align:center;'>
<span>Page <span class='pageNumber'></span> of <span class='totalPages'></span></span>
</div>",
Margins = new PdfMargins
{
Top = "60mm", // Extra space for header
Bottom = "40mm" // Extra space for footer
}
}
};
const pdf = await page.pdf({
format: 'A4',
displayHeaderFooter: true,
headerTemplate: `
<div style="font-size:10px; width:100%; text-align:center; color:#666;">
My Company - Confidential
</div>
`,
footerTemplate: `
<div style="font-size:10px; width:100%; text-align:center; color:#666;">
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</div>
`,
margin: { top: '60mm', bottom: '40mm', left: '20mm', right: '20mm' }
});
Page Break Control
Control where page breaks occur in multi-page documents:
<style>
/* Force page break before element */
.page-break-before { page-break-before: always; }
/* Force page break after element */
.page-break-after { page-break-after: always; }
/* Avoid breaking inside element */
.keep-together { page-break-inside: avoid; }
/* Table rows - avoid orphan headers */
thead { display: table-header-group; }
tr { page-break-inside: avoid; }
</style>
<div class="section">
<h2>Section 1</h2>
<p>Content...</p>
</div>
<div class="page-break-before">
<h2>Section 2 (New Page)</h2>
<p>This starts on a new page</p>
</div>
Print-Optimized CSS
<style>
@media print {
/* Hide screen-only elements */
.no-print, nav, .sidebar { display: none !important; }
/* Ensure backgrounds print */
* { -webkit-print-color-adjust: exact !important; }
/* Reset margins for print */
body { margin: 0; padding: 20mm; }
/* Optimize links */
a[href]:after { content: " (" attr(href) ")"; font-size: 0.8em; }
}
</style>
Landscape & Custom Sizes
// Landscape A4
var landscapeOptions = new PdfOptions
{
Format = PdfPageFormat.A4,
Landscape = true
};
// Custom size (e.g., label printing)
var labelOptions = new PdfOptions
{
Format = PdfPageFormat.Custom,
Width = "4in",
Height = "2in"
};
Performance Tips
| Tip | Description |
|---|---|
| Reuse browser instance | Don't launch/close for each PDF |
| Limit external resources | Embed fonts & images as base64 |
Use networkidle | Wait for all resources to load |
| Set timeouts | Prevent hanging on slow content |
| Cache rendered PDFs | Enable EnableCaching option |
// Singleton browser pattern in .NET
builder.Services.AddSingleton<IPdfGenerator, PlaywrightPdfGenerator>();
Error Handling
try
{
var result = await _pdf.GenerateWithResultAsync(request);
if (!result.Success)
{
_logger.LogError("PDF generation failed: {Error}", result.ErrorMessage);
return StatusCode(500, new { error = result.ErrorMessage });
}
_logger.LogInformation(
"Generated PDF: {Pages} pages, {Size} bytes in {Time}ms",
result.PageCount, result.SizeBytes, result.GenerationTimeMs);
return File(result.PdfBytes, "application/pdf");
}
catch (PdfGenerationException ex)
{
return StatusCode(500, new { error = ex.Message });
}