Release history for CobaltPDF & CobaltPDF.Requests
v1.6.4
Fixed
Render latency on network-restricted hosts. Renders that took 16–45 s on servers with restricted outbound network access (hanging font/analytics/CDN requests that never reach network idle) no longer burn hard-coded internal waits. When an explicit wait strategy is configured (ForDelay, ForSelector, ForJavaScript, ForSignal), the fixed 5 s client-side redirect probe on URL renders and the fixed 10 s network-idle wait before custom JS are now skipped entirely — the strategy already defines page readiness.
Browser pool no longer discards warm browsers under concurrent load. Previously, healthy browsers were disposed whenever the pool held more than MinSize, so every concurrent render beyond the first launched a cold Chromium and threw it away — typically adding several seconds per render on Windows Server, where antivirus scans each launch. Healthy browsers are now recycled up to MaxSize and kept warm; a background reaper reclaims browsers idle longer than PoolOptions.IdleShrinkAfter (default 60 s), never shrinking below MinSize.
Added
WithNetworkIdleTimeout(TimeSpan) (and PdfOptions.NetworkIdleTimeout) — caps all internal network-idle waits: the pre-custom-JS wait, the lazy-load scroll waits, and the default network-idle wait strategy (previously an implicit 30 s, now explicit and configurable). TimeSpan.Zero skips them entirely.
WithClientRedirectWait(TimeSpan) / WithoutClientRedirectWait() (and PdfOptions.ClientRedirectTimeout) — explicit control over the client-side redirect probe on URL renders, overriding the automatic skip in either direction.
PoolOptions.IdleShrinkAfter (default 60 s) — how long a warm browser may sit idle before the pool reclaims it. TimeSpan.Zero restores the previous dispose-on-return behavior for memory-critical hosts.
Per-stage timing diagnostics. Every render now logs stage durations (acquire pooled browser, navigate, client-redirect probe, custom JS, wait strategy, lazy-load scroll, pdf capture, total render) as [Browser TIMING] entries through the existing CobaltEngine.LoggingMode / OnBrowserLog pipeline — zero overhead when logging is disabled, so support cases can pinpoint the slow stage immediately.
Compatibility
Behavioral change: with an explicit wait strategy configured, the 5 s redirect probe and the 10 s pre-custom-JS idle wait no longer run. Callers that relied on those implicit waits alongside an explicit strategy can re-enable them via WithClientRedirectWait(...) / WithNetworkIdleTimeout(...).
Behavioral change: after a burst of concurrent renders, the pool now holds up to MaxSize browsers warm for up to IdleShrinkAfter — higher steady-state memory for up to 60 s. Set IdleShrinkAfter = TimeSpan.Zero for the old behavior.
Default-configuration single renders (no custom JS, default wait strategy) behave identically to 1.6.3. No public API was removed — all changes are additive options and methods.
v1.6.3
Added
WithSkipTrailingBlankPage() (and PdfOptions.SkipTrailingBlankPage, plus PdfRequest.SkipTrailingBlankPage via CobaltPDF.Requests 1.6.2) — suppresses the trailing blank page produced when the document's last element carries page-break-after: always, a common pattern when generating pages in a loop. Opt-in; default output is unchanged.
Security
Dependency security update.Magick.NET-Q8-AnyCPU moves to 14.16.0, clearing the ImageMagick advisories reported against 14.14.0 (used internally to recompress images during post-processing). Microsoft.Extensions.DependencyInjection and System.Formats.Asn1 move to 10.0.11. dotnet list package --vulnerable now reports no vulnerable packages; rendering behaviour is unchanged.
Changed
Output PDFs now identify as CobaltPDF./Producer no longer leaks the internal post-processing library ("PDFsharp … (Original: Skia/PDF …)") and /Creator no longer leaks the headless browser User-Agent — in the doc-info, the XMP packet, and the trailer comment. A Producer/Creator supplied via WithMetadata still wins. Raw output via WithCompression(false) without metadata remains byte-for-byte untouched, and encrypted documents keep the previous strings.
Friendlier licensing errors. Specific failures (invalid signature, expired license, ended support period, revoked key) now surface their actionable message directly instead of a generic "License validation failed."; the generic wrapper (malformed keys) now explains the likely cause and notes that evaluation needs no key.
CobaltPDF.Requests dependency updated to v1.6.2.
v1.6.2
Fixed
Azure preset no longer breaks multi-page PDFs.CloudEnvironment.ConfigureForAzure (and ConfigureForLowMemory) no longer add --single-process — that flag crashes the Chromium renderer on multi-page or non-trivial documents (only trivial single-page renders survived it). 1.6.1 could fail real renders on Azure when these presets were used, so upgrading from 1.6.1 is recommended. The presets now use the stable multi-process model.
Changed
The bundled Linux dependencies (added in 1.6.1) now activate only when the host is missing Chromium's graphics stack, so Linux hosts that already provide the libraries render exactly as before.
v1.6.1
Added
Runs on stock Linux with no container. The package now ships Chromium's OS-level dependencies (system libraries, NSS modules, and base fonts) and points the browser's loader at them automatically on Linux — so the Chromium edition runs on a stock Azure Functions Linux plan or a slim container with a plain code deploy (no custom container, no apt). On Linux hosts that already provide the libraries, nothing changes: the host's own libraries and fonts are used exactly as before, and the bundled set is used only when the host is missing them.
CobaltPDF.Requests dependency pinned to v1.6.1.
v1.6.0
Added
WithCompression(bool) — output PDFs now re-encode embedded images to shrink the file (typically several times smaller on image-heavy pages). Call WithCompression(false) for raw, lossless output. Powered by Magick.NET (Apache-2.0).
WithViewportSize(width[, height]) — sets the render viewport; a tall height triggers IntersectionObserver lazy images without scrolling.
WithEagerImages() — forces lazy-loaded images to load before rendering, additionally promoting the JavaScript data-src/data-srcset convention the print path cannot.
Pool backpressure & metrics. New PoolOptions.MaxQueueDepth + PoolBusyException let a saturated pool fast-fail extra requests so the host can return HTTP 503 instead of a slow timeout (default 0 = unbounded). New CobaltEngine.GetPoolStatistics() / CobaltPoolStatistics expose live pool gauges and lifetime counters for health endpoints.
Changed
Desktop-layout rendering by default. Renders now capture the full desktop layout (≈1280 px wide) scaled to fit the page — instead of reflowing to the narrow print width. The paper keeps its true size (e.g. A4). Set WithMediaType(CssMediaType.Print) to restore the old Chrome-print reflow.
Image compression is on by default (see above), so output is now slightly lossy unless you call WithCompression(false).
Default User-Agent is now a desktop Chrome UA (via PdfOptions.DefaultUserAgent) so UA-sensitive sites serve consistent desktop markup. Override with WithUserAgent(...).
Auto-sized concurrency.PoolOptions.MaxSize now defaults to a host-aware value — the smaller of the vCPU count and what fits in ~75% of detected memory, clamped 1–8 — instead of a fixed 5, so it stays safe on memory-constrained hosts. Always overridable.
CobaltPDF.Requests dependency updated to v1.6.1.
Deprecated
WithoutPostProcessing() — use WithCompression(bool) instead (WithoutPostProcessing() is equivalent to WithCompression(false)). It still compiles, and is no longer a no-op on this edition.
Compatibility
No public API was removed; existing code compiles and runs unchanged. The default output now differs (desktop-scaled layout + image compression) — combine WithMediaType(CssMediaType.Print) and WithCompression(false) to reproduce v1.5.x output.
v1.5.0
Added
PDF page splitting, extraction & merging. New PdfDocument members: PageCount, ExtractPage(int), ExtractPages(start, end), ExtractPages(IEnumerable<int>), SplitIntoPages(), and static FromFile(path), FromBytes(data), and Merge(params PdfDocument[]). Works on any PDF — freshly rendered or loaded from disk — on any OS. Page indices are 0-based; out-of-range indices throw ArgumentOutOfRangeException.
Watermark rasterization. New opt-in WatermarkOptions.Rasterize flag (fluent .WithRasterize()) flattens a watermark into a high-resolution image baked into every page — no selectable text and no separate deletable object in a PDF editor. Tamper-resistance for confidential documents; default behaviour is unchanged.
WithoutPostProcessing() added as an accepted no-op. Chromium's PDF backend already subsets fonts and compresses images natively, so the method has no effect here.
Security
Encryption upgraded to AES-256 (security handler V5/R6, previously AES-128). The WithEncryption(...) API, PdfEncryptionOptions, and all password/permission behaviour are unchanged — only the cipher strength improved. Both CobaltPDF libraries now produce identical AES-256 protection from identical options.
Changed
CobaltPDF.Requests dependency updated to v1.5.0 — a serialized PdfRequest can now request a rasterized watermark and carry the new SkipPostProcessing flag.
Deployment documentation corrected and expanded after validation on real Azure infrastructure: Linux Azure Functions require a custom container for Chromium (the stock image lacks its system libraries) — the Azure Functions guide and docs now carry validated container walkthroughs and engine toggles.
Compatibility
Fully backward compatible — no public API was renamed or removed, and existing code compiles and runs unchanged.
v1.4.1
Added
WithUserAgent, WithHttpHeader, and WithHttpHeaders are now declared on the IPdfGenerator and IPdfGeneratorFinal interfaces (previously only available on CobaltEngine), so code holding an interface reference gets the same methods via IntelliSense.
Fixed
AddCookie(name, value) without an explicit domain no longer throws "Invalid cookie fields" when the final URL is localhost, an IPv4/IPv6 address, or a single-label intranet hostname. The cookie is now correctly registered as a standard host-only cookie. Cookie inference for public domains is unchanged.
v1.4.0
Security
Updated bundled Chromium from 2026.2.1 to 2026.5.16, addressing upstream security advisories.
Removed
Dropped the net6.0 target. The package now targets net8.0 (compatible with .NET 8, 9, and 10). Consumers on .NET 6 should stay on v1.3.0 or upgrade their runtime — .NET 6 reached end of Microsoft support in November 2024.
Changed
Bumped Microsoft.Extensions.DependencyInjection from 10.0.3 to 10.0.8.
Bumped System.Formats.Asn1 from 10.0.3 to 10.0.8.
Bumped Microsoft.Playwright from 1.58.0 to 1.60.0.
v1.3.0
Added
Multi-target support: the package now ships builds for both net6.0 and net8.0, broadening compatibility with projects on .NET 6, 7, 8, 9, and 10.
Changed
CobaltPDF.Requests dependency updated to v1.3.0 (now targets netstandard2.0).
v1.2.2
Fixed
Fixed Chromium default header/footer appearing when only one template is provided.
Fixed WithLazyLoadPages not working when combined with WithCustomJS or WithWaitStrategy.
Changed
WithCustomJS now waits for the page to be fully loaded before executing, so dynamically-injected elements (e.g. cookie consent buttons) are available.
Client-side redirects (e.g. bbc.com → bbc.co.uk) are now detected before cookies, custom JS, and wait strategies run.
v1.2.0
Changed
Renamed .Landscape() to .WithLandscape() for fluent API consistency.
Renamed .UseGrayscale() to .WithGrayscale() for fluent API consistency.
Renamed .EmulateMediaType() to .WithMediaType() — shorter and consistent with the With* convention.
Renamed .WaitFor() to .WithWaitStrategy() to avoid confusion with async operations.
Renamed .ReloadAfterStorageSet() to .WithReloadAfterStorage() for fluent API consistency.
Renamed .ConfigureFonts() to .WithFonts() — shorter and consistent with the With* convention.
v1.1.0
Added
Fluent .WithWatermark() API for text and HTML watermarks with configurable opacity, rotation, and position.
PDF metadata support — set title, author, subject, keywords, and creator via .WithMetadata().
CloudEnvironment.ConfigureForAzure preset for Azure App Service and Container Apps deployments.
New .ScrollPage() option to trigger lazy-loaded images before capture.
Changed
Default pool MaxSize increased from 4 to 8 for better throughput on multi-core hosts.
Improved browser recycling logic — instances are now recycled after 50 renders (previously 100).
Fixed
Resolved rare deadlock when calling RenderUrlAsPdfAsync with a CancellationToken that fires during navigation.
Fixed header/footer templates not respecting @media print styles.
v1.0.1
Fixed
Fixed PreWarmAsync() throwing ObjectDisposedException when called immediately after Configure() on Linux containers.
Corrected paper size calculation for custom dimensions specified in millimetres.
Resolved an issue where AddCookie() cookies were not sent on the initial page load when using RenderUrlAsPdfAsync.
v1.0.0
Added
Initial release of CobaltPDF — a high-performance HTML-to-PDF rendering engine for .NET.
Chromium-powered rendering with full support for modern CSS (Grid, Flexbox, custom properties, animations).
Managed browser pool with configurable MinSize, MaxSize, and automatic recycling.
Fluent API for PDF generation — chain options and call a single terminal method.
Thread-safe singleton design with isolated browser contexts per render.
Cookie, localStorage, and sessionStorage injection per render.
Custom HTTP headers and User-Agent per render.
Header and footer HTML templates with page number, total pages, and date tokens.
PDF encryption with user/owner passwords and granular permission control.
ASP.NET Core dependency injection via services.AddCobaltPdf().
Companion package CobaltPDF.Requests for lightweight microservice clients.
v1.6.2
Added
PdfRequest.SkipTrailingBlankPage (and PdfRequestBuilder.WithSkipTrailingBlankPage(bool)) — suppresses the trailing blank page produced when the document's last element carries page-break-after: always. Defaults to false, so existing payloads render unchanged. Honoured by CobaltPDF 1.6.3+.
v1.6.1
Added
PdfRequest.Compress (and PdfRequestBuilder.WithCompression(bool)) — controls output PDF compression; defaults to true. Maps to WithCompression(bool) in CobaltPDF 1.6.0+.
PdfRequest.ViewportWidth / ViewportHeight (and PdfRequestBuilder.WithViewportSize(width[, height])) — sets the render viewport; a tall height triggers IntersectionObserver lazy images without scrolling.
PdfRequest.ForceEagerImages (and PdfRequestBuilder.WithEagerImages()) — forces lazy-loaded images to load before rendering. Honoured by both editions.
Deprecated
PdfRequestBuilder.WithSkipPostProcessing() — use WithCompression(false) instead. The legacy SkipPostProcessing property is retained as the inverse of Compress for backward compatibility.
Compatibility
Purely additive — existing PdfRequest JSON (including the older SkipPostProcessing flag) deserializes and behaves exactly as before.
v1.6.0
Added
Fluent builder for PdfRequest — mirrors the CobaltEngine fluent API, so authoring a request reads the same as rendering one. Start with PdfRequest.ForUrl(url) or PdfRequest.ForHtml(html), chain .WithPaperFormat(), .WithMargins(), .WithHeader(), .WithWatermark(), .WithEncryption(), .WithMetadata(), .AddCookie() and more, then call .Build(). PdfRequest.ToBuilder() adapts an existing instance.
Compatibility
Purely additive — PdfRequest is unchanged and object-initializer construction works exactly as before. The fluent path produces an identical PdfRequest (and identical JSON on the wire).
v1.5.0
Added
PdfRequest.SkipPostProcessing (bool, default false) — ask the rendering service to skip its PDF post-processing pipeline and return raw engine output: lower memory and latency, larger files; watermark, encryption, and metadata are ignored when set. Accepted for forward compatibility; CobaltPDF's PDF backend already optimises natively.
Compatibility
One new optional JSON property ("skipPostProcessing"). Older clients that don't send it get the existing behaviour; older servers ignore the unknown property — mixed-version client/server combinations keep working.
v1.4.0
Added
PdfRequestWatermark.Rasterize (bool, default false) — ask the rendering service to flatten a watermark into a non-editable image baked into every page, matching the new WatermarkOptions.Rasterize capability in CobaltPDF.
Compatibility
One new optional JSON property ("rasterize") on the watermark object. Older clients that don't send it get the existing vector behaviour; older servers ignore the unknown property — mixed-version client/server combinations keep working.
v1.3.0
Changed
Retargeted from net8.0 to netstandard2.0 for maximum compatibility — usable from .NET Framework 4.6.1+, .NET Core 2.0+, and all modern .NET versions.
v1.2.0
Added
Added PdfRequestMargins, PdfRequestWatermark, PdfRequestEncryption, and PdfRequestMetadata models.
Added PdfResponse with FromBytes() and ToStream() helpers.
v1.0.0
Added
Initial release — lightweight PdfRequest and PdfResponse models for sending PDF generation requests to a CobaltPDF-powered microservice.
Full JSON-serialisable request model mirroring the CobaltPDF fluent API.
Cookie, header, encryption, metadata, watermark, and wait strategy support.