PuppeteerPagePool
PuppeteerPagePool is a callback-based Chromium page pool for PuppeteerSharp workloads like HTML-to-PDF, screenshots, and repeated server-side rendering.
Install
dotnet add package PuppeteerPagePool
Target Frameworks
net10.0
Core Concepts
- You run rendering work via
IPagePool.ExecuteAsync(...). - The callback receives an
ILeasedPage. ILeasedPageis lease-scoped and invalid after callback completion.- The pool owns page lifecycle (reset, reuse, replacement, shutdown).
Public API
IPagePool
public interface IPagePool : IAsyncDisposable
{
ValueTask ExecuteAsync(
Func<ILeasedPage, CancellationToken, ValueTask> operation,
CancellationToken cancellationToken = default);
ValueTask<TResult> ExecuteAsync<TResult>(
Func<ILeasedPage, CancellationToken, ValueTask<TResult>> operation,
CancellationToken cancellationToken = default);
ValueTask<PagePoolHealthSnapshot> GetSnapshotAsync(CancellationToken cancellationToken = default);
}
ILeasedPage
ILeasedPage exposes rendering-focused operations (navigation, content loading, waiting, JS evaluation, PDF, screenshot, headers, cookies, auth, viewport) over a lease-scoped page.
PagePoolHealthSnapshot
Runtime snapshot includes:
PoolSizeAvailablePagesLeasedPagesWaitingRequestsBrowserConnectedAcceptingLeasesUptimeLastHealthCheck
Registration (DI)
using Microsoft.Extensions.DependencyInjection;
using PuppeteerPagePool;
using PuppeteerPagePool.Abstractions;
using PuppeteerSharp;
var services = new ServiceCollection();
services.AddPuppeteerPagePool(options =>
{
options.PoolSize = 4;
options.AcquireTimeout = TimeSpan.FromSeconds(20);
options.ShutdownTimeout = TimeSpan.FromSeconds(20);
options.ResetTargetUrl = "about:blank";
options.LaunchOptions = new LaunchOptions
{
Headless = true,
Timeout = 120_000,
Args =
[
"--disable-dev-shm-usage",
"--disable-gpu",
"--no-sandbox"
]
};
});
await using var provider = services.BuildServiceProvider();
var pool = provider.GetRequiredService<IPagePool>();
Non-DI Usage
using PuppeteerPagePool;
using PuppeteerPagePool.Abstractions;
using PuppeteerSharp;
await using var pool = await PagePoolFactory.CreateAsync(options =>
{
options.PoolSize = 4;
options.ResetTargetUrl = "about:blank";
options.LaunchOptions = new LaunchOptions
{
Headless = true
};
});
Quick Usage
var pdf = await pool.ExecuteAsync(async (page, cancellationToken) =>
{
await page.SetContentAsync("<html><body><h1>Report</h1></body></html>");
await page.WaitForNetworkIdleAsync();
return await page.PdfDataAsync(new PdfOptions
{
PrintBackground = true
});
});
Screenshot
var image = await pool.ExecuteAsync(async (page, cancellationToken) =>
{
await page.GoToAsync("https://example.com");
await page.WaitForNetworkIdleAsync();
return await page.ScreenshotDataAsync(new ScreenshotOptions
{
FullPage = true
});
});
Configuration (PagePoolOptions)
PoolNamePoolSizeAcquireTimeoutWarmupOnStartupShutdownTimeoutDrainOnShutdownResetTargetUrlResetNavigationTimeoutResetWaitConditionsClearStorageOnReturnClearCookiesOnReturnMaxPageUsesLaunchOptionsConnectOptions
Validation rules include:
LaunchOptionsandConnectOptionscannot both be set.ResetTargetUrlmust be an absolute URI.- Timeouts and limits must be positive.
Browser Boot Behavior
When launching locally:
- Headless mode is always enforced.
- If
LaunchOptions.ExecutablePathis not set,PUPPETEER_EXECUTABLE_PATHis checked. - If still not found, Chromium is downloaded via
BrowserFetcher.
When connecting remotely:
ConnectOptionsmust containBrowserWSEndpointorBrowserURL.
Pool Behavior
After successful callback completion, the pool resets the page and returns it to the channel.
A page is replaced when:
- callback throws
- page is closed
- page exceeds
MaxPageUses - page preparation/reset fails
If browser disconnects, the pool rebuilds runtime and repopulates pooled pages.
Exceptions
PagePoolAcquireTimeoutExceptionPagePoolDisposedExceptionPagePoolUnavailableExceptionPageOperationExceptionPagePoolCircuitOpenException
Operational Guidance
- Keep callbacks short.
- Return bytes/DTOs from callbacks, not page references.
- Never cache
ILeasedPagebeyond callback scope. - Prefer a fast reset URL (
about:blankor internal lightweight route). - Size
PoolSizeaccording to workload and host capacity.