Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To capture network traffic with PuppeteerSharp, subscribe to the page’s request and response lifecycle events before navigating or triggering the action you want to inspect. Record outgoing details in Request, response metadata and bytes in Response, and completion or failure in RequestFinished and RequestFailed. For a complete response body, use IResponse.BufferAsync() and retain the returned bytes.

Capture request and response data with page events

Page events let you observe traffic without changing how requests are handled. The example below records request context, response metadata and response bytes, then marks successful completions or failures. Attach handlers before navigation so the initial page requests are included.

This example uses the event and method names in PuppeteerSharp’s API reference. The documentation consulted does not establish a package version, so check the signatures against the NuGet version installed in your project.

using PuppeteerSharp;

var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
    Headless = true
});

try
{
    var page = await browser.NewPageAsync();

    page.Request += (_, request) =>
    {
        Console.WriteLine($"REQUEST {request.Method} {request.ResourceType} {request.Url}");
        if (request.PostData is not null)
        {
            Console.WriteLine($"  post data: {request.PostData}");
        }
    };

    page.Response += async (_, response) =>
    {
        var request = response.Request;
        Console.WriteLine($"RESPONSE {response.Status} {response.Url}");
        Console.WriteLine($"  request: {request.Method} {request.ResourceType}");
        Console.WriteLine($"  from cache: {response.FromCache}; from service worker: {response.FromServiceWorker}");

        var bytes = await response.BufferAsync();
        var fileName = $"response-{Guid.NewGuid():N}.bin";
        await File.WriteAllBytesAsync(fileName, bytes);
        Console.WriteLine($"  saved {bytes.Length} bytes to {fileName}");
    };

    page.RequestFinished += (_, request) =>
    {
        Console.WriteLine($"FINISHED {request.Method} {request.Url}");
    };

    page.RequestFailed += (_, request) =>
    {
        Console.WriteLine($"FAILED {request.Method} {request.Url}: {request.FailureText}");
    };

    await page.GoToAsync("https://example.com");
}
finally
{
    await browser.CloseAsync();
}

The event handlers above print each record as it arrives. For an application that needs a coherent capture, store records in a collection or write them to a structured log, keyed by request identity and including timestamps. The matching request is available from a response’s Request property.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What each lifecycle event means

Event What to record Interpretation
Request URL, method, resource type, and post data when available. The page issued a request. Post data may not always be available in decoded form.
Response Response URL, status, status text, headers, cache and service-worker indicators, and the associated request. A response was received. Use BufferAsync() to obtain its body as bytes.
RequestFinished Completion state for the associated request. The response body has downloaded and the request is complete.
RequestFailed Failure text and request context. The request failed rather than completing successfully. It can fail before a response event.

An HTTP error status is still a response; do not treat a non-2xx status by itself as proof of a transport failure. A failed request is reported through RequestFailed, while a response’s status belongs in the response record.

Store full response bodies safely

BufferAsync() returns body bytes, so it is the suitable default when you need to preserve an entire response without assuming it is text. The example writes each body to a uniquely named binary file. In a real capture tool, associate the file or byte array with the response URL, status, headers and matching request.

  • Use a byte buffer for binary content or when the content type is uncertain.
  • Decode bytes to text only when the response content type and encoding make that appropriate.
  • Parse JSON only after confirming the body is JSON and handling parsing errors.
  • Apply storage limits or filtering for large responses, and take care not to retain sensitive headers or bodies unintentionally.

The PuppeteerSharp Page reference also demonstrates a text-oriented response use case with TextAsync(). For general-purpose full-body capture, bytes avoid imposing a text interpretation prematurely.

Handle redirects as separate requests

A redirect is not one request whose URL simply changes. The redirect response completes the current request, then the browser issues a new request to the redirected URL. Keep both request records to preserve the sequence; where useful, inspect the request’s redirect chain to relate the hops.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Observation versus interception

Do not enable interception just to capture traffic. Event subscriptions observe requests and responses; interception is for changing their handling.

Approach Use it when What it does
Lifecycle event handlers You need diagnostics, logging, request metadata or response bodies. Observes traffic without intentionally modifying request handling.
Request interception You need to abort a request, continue with overrides or fulfill it with a synthetic response. Changes handling and requires the handler to resolve requests as intended.

When modification is needed, enable interception with SetRequestInterceptionAsync(true) and implement the intended continue, abort or fulfill behavior. Leaving an intercepted request unresolved can interfere with page loading. Exact operational details can vary with the backend and PuppeteerSharp version, so confirm the API for the version you use.

Troubleshoot missing or incomplete captures

  • Initial requests are absent: register all event handlers before calling GoToAsync or triggering the page action.
  • A request has no response record: inspect RequestFailed; failures may happen before any response arrives.
  • A response body is not readable as text: retain the result of BufferAsync() as bytes, then decode only with a suitable content type and encoding.
  • A redirect appears to have multiple entries: preserve each hop; redirects finish one request and initiate another.
  • A non-2xx response was marked as a failure: keep HTTP response status separate from request-failure events.
  • Interception changes or stalls page behavior: use observation events if modification is unnecessary, or ensure intercepted requests are continued, aborted or fulfilled deliberately.
  • Sample code does not match your package: verify event signatures and methods against the documentation corresponding to your installed PuppeteerSharp NuGet version.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need a website screenshot rather than raw request and response capture, ScreenshotNeo provides a one-call screenshot API and an MCP server for AI agents. It does not expose the PuppeteerSharp network lifecycle described above.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie and consent banners, newsletter popups and chat widgets are removed before capture; bot checks, blank pages and failed loads are not billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for ScreenshotNeo’s free plan.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.