Free tools Windows power users keep installed

One-click scans. No signup required.

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

“Protocol error (Page.captureScreenshot): Target closed” means Puppeteer tried to use a page target that no longer exists. Usually the page was closed while an operation was still pending, but the same message can also hide a disconnected browser, a Chromium crash, missing Linux libraries, or a container/runtime mismatch. Fix it by enforcing strict await ordering, finding every competing close path, and then checking browser stderr and runtime compatibility if the failure occurs during launch or at random.

What “Target closed” means

Puppeteer sends screenshot commands through Chrome DevTools Protocol (CDP). When page.screenshot() runs, the relevant command is Page.captureScreenshot. Chrome has a page target for the tab; if that target disappears before the command completes, CDP returns Target closed.

The message identifies a lifecycle symptom, not one universal cause. The useful question is: what closed the target, and when?

When it fails Most likely branch What to inspect first
During or immediately after page.screenshot() Premature page, context, or browser closure; an unresolved concurrent operation Every close(), timeout callback, error handler, and promise that can run at the same time
Immediately after page.evaluate() Evaluation or an exposed callback is still running while cleanup starts Whether the evaluation is awaited and whether its callbacks outlive the page
At launch or while creating a page Chromium failed to start, crashed, or cannot load a required shared library Chromium stderr, exit code, image libraries, and executable compatibility
Intermittently in Docker or Alpine Node, Puppeteer, Chromium, base image, or launch-flag incompatibility Exact versions and a reproduction with experimental flags removed

First fix: await the complete sequence

Do not let cleanup run until navigation and the screenshot have both resolved. The smallest reliable test is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto(url, {waitUntil: 'networkidle2'});
await page.screenshot({path: 'shot.png', fullPage: true});

await page.close();
await browser.close();

The critical detail is not the delay or the networkidle2 choice. It is that each operation is awaited and cleanup follows the completed screenshot. Closing a page, context, or browser from a finally block is correct only when all work that uses that target has finished.

Use lifecycle-safe cleanup

For application code, nested try/finally blocks make the ownership and order explicit. The page closes before the browser, and a failed navigation cannot skip cleanup.

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  try {
    await page.goto(url, {waitUntil: 'networkidle2'});
    await page.screenshot({path: 'shot.png', fullPage: true});
  } finally {
    if (!page.isClosed()) {
      await page.close();
    }
  }
} finally {
  await browser.close();
}

This is a safe sequencing pattern, not a guarantee against a Chromium process crash. If the browser dies, the protocol target disappears regardless of how carefully the JavaScript is ordered.

Find the code path that closed the target

Search the whole request path for page.close(), browser.close(), browser-context closure, timeout callbacks, and error handlers. A common failure is a timeout or catch block that closes the page while the normal path is still taking a screenshot.

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

Add temporary lifecycle logging around both operations and events:

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
const started = Date.now();
const mark = (message) => console.error(`[${Date.now() - started}ms] ${message}`);

page.on('close', () => mark('page close event'));
page.on('error', (error) => mark(`page error: ${error.message}`));
browser.on('disconnected', () => mark('browser disconnected'));

mark('goto start');
await page.goto(url, {waitUntil: 'networkidle2'});
mark('goto complete');
await page.screenshot({path: 'shot.png', fullPage: true});
mark('screenshot complete');

Also log process exit and the code that initiates every close. The last log line tells you whether the target vanished before the screenshot began, during it, or after it had already completed.

Promise.race can leave work running

Promise.race() settles when one promise wins; it does not automatically cancel the others. If a timeout, navigation, evaluation, or screenshot promise loses the race, it may continue using the page. Closing the page as soon as the winner resolves can therefore make the losing operation fail with Target closed.

Keep references to concurrent operations and do not close the target until the remaining work has settled or has an explicit cancellation path. For operations that cannot be cancelled, avoid racing them against cleanup; perform the work sequentially and enforce a timeout at a higher level that can safely dispose of the whole browser job.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const navigation = page.goto(url, {waitUntil: 'networkidle2'});
const timeout = new Promise((_, reject) => {
  setTimeout(() => reject(new Error('navigation timeout')), 30000);
});

try {
  await Promise.race([navigation, timeout]);
  await page.screenshot({path: 'shot.png'});
} finally {
  // Do not close the page here while an unhandled navigation promise can
  // still be running. Track and settle the outstanding operation first.
  await navigation.catch(() => {});
  if (!page.isClosed()) await page.close();
}

The exact cancellation strategy depends on the operation and Puppeteer version. The invariant is constant: no pending page operation may outlive the page it uses.

Await evaluation and exposed callbacks before cleanup

If the error appears after page.evaluate(), inspect code inside the evaluation and any functions exposed from Node. A returned promise inside the page must be awaited by Puppeteer, and Node-side callbacks must finish before you close the page. Cleanup that starts immediately after a fire-and-forget evaluation can remove the target while that work is still active.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
await page.evaluate(async () => {
  // Complete asynchronous page work before evaluate resolves.
  await document.fonts.ready;
  return document.title;
});

// Only now begin screenshot and cleanup.
await page.screenshot({path: 'shot.png'});

Remove untracked timers, event listeners, and callbacks that can touch the page after the main function returns. If an exposed function starts asynchronous work, return and await its promise instead of launching it without a handle.

When the browser, not your page code, is failing

A target-closed protocol message can be the final symptom of a Chromium startup failure or crash. Re-run the job with Chromium stderr captured and record the process exit code. Look for the first operating-system error rather than focusing only on the final CDP exception.

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

Missing shared libraries

One documented launch failure reports error while loading shared libraries: libgobject-2.0.so.0: cannot open shared object file. Install the library in the image or use a base image that supplies the dependencies required by the Chromium build you are launching. A JavaScript change cannot repair a missing native library.

Docker and Alpine

Intermittent errors such as Target.setAutoAttach: Target closed have been reported when Node, Puppeteer, Chromium, and an Alpine or other container image are not compatible. Build a minimal reproduction, compare all four versions, capture stderr, and remove experimental launch flags one at a time. Keep only flags required by your security and sandbox policy; adding random flags can mask the real incompatibility.

Browser crashes during capture

If the page closes without any application-level close call, inspect Chromium’s crash output, container memory limits, and the URL that triggers the crash. Reproduce with one page and one screenshot before changing concurrency. The protocol error is then evidence that the browser process or target disappeared, not proof that page.screenshot() itself is defective.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Record versions before comparing fixes

Puppeteer changes error classes and target/session wording over time. Record the exact Puppeteer package version, Node.js version, Chromium version or executable path, operating system, and container/base-image version with every report. A stack trace from an older release may not map one-to-one to a current release even when the underlying lifecycle problem is similar.

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

Keep the launch configuration, URL characteristics, concurrency, and whether the failure is deterministic. This separates a reproducible sequencing bug from an environment-only crash.

A practical diagnostic sequence

  1. Make the call explicit. Use await page.goto(...), then await page.screenshot(...), then close the page.
  2. Instrument closure. Log every page, context, and browser close, plus page errors and browser disconnection.
  3. Inspect races. Retain promises passed to Promise.race(); settle or cancel losers before disposal.
  4. Audit evaluation. Await page.evaluate() and exposed functions, including asynchronous work they start.
  5. Separate launch from lifecycle. Capture Chromium stderr and exit status if the failure occurs at startup or without a close call.
  6. Validate the runtime. Check shared libraries and compare Node, Puppeteer, Chromium, and container versions.
  7. Reduce concurrency. Reproduce with one browser, one page, and one URL before tuning workers or retries.

Common symptoms and fixes

Symptom Likely cause Action
The stack ends at Page.captureScreenshot and a close log appears first Page closed before the screenshot promise resolved Await the screenshot and move all cleanup after it; remove competing timeout or error-handler closes
Failure follows a timeout race The losing promise is still using the target Track the losing promise and settle or cancel it before closing
Failure follows page.evaluate() Evaluation or an exposed callback remains active Return and await asynchronous work; remove fire-and-forget callbacks
Failure occurs during launch with a native-library message in stderr Chromium cannot load its dependencies Install the named library or change to a compatible image/runtime
Failure is random only in a container Version, resource, or launch-flag incompatibility Capture stderr, compare versions, remove experimental flags, and reproduce at lower concurrency
Only old issue advice matches the stack trace Puppeteer changed target/session error reporting Check the exact installed version before applying a historical workaround

Prevent the error in production

  • Give each screenshot job clear ownership of its browser, context, and page.
  • Await every Puppeteer operation that touches a target.
  • Keep timeout, retry, and cleanup logic from closing a page owned by another task.
  • Use structured logs for navigation start/completion, screenshot start/completion, close events, disconnection, stderr, and exit code.
  • Start with bounded concurrency and increase it only after a single-job reproduction is stable.
  • Pin and record Node, Puppeteer, Chromium, and container versions.
  • Test the actual container image, not only a developer workstation.
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 only need a reliable website image rather than a Puppeteer runtime to maintain, ScreenshotNeo provides a single HTTP request for PNG, JPEG, WebP, or PDF output. Its capture pipeline accepts cookie and consent banners, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and lets you turn those steps off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and whether the request was billed.

For a direct screenshot, see the ScreenshotNeo API documentation and run:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also exposes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It supports full-page captures with lazy images loaded, CSS-selector element shots, device presets or custom viewports, dark mode, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, and a usage API. All features are available on every plan.

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

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing provides two months free. Create a free ScreenshotNeo account to try it without a card.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

FAQ

Does adding a sleep always fix the error?

No. A delay can change timing without correcting a close race, an unresolved promise, or a browser crash. The fix is to identify and order the operation that owns the target.

Can a website itself cause Target closed?

A page can trigger a Chromium crash or expose an environment problem, but the error still means the target disappeared before CDP completed its command. Use stderr and a minimal reproduction to distinguish page-specific crashes from application cleanup.

Should I close the page or the browser after a failed screenshot?

Follow the ownership hierarchy: finish or abandon all operations using the page, close the page, then close its browser. If Chromium has already disconnected, collect diagnostics and let the failed browser job terminate before starting a clean one.

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

Why do reports with the same text have different fixes?

Puppeteer versions can report target and session failures differently, and the same text can result from premature closure, a race, missing libraries, or a crash. Version and environment details are essential for matching a remedy.

Frequently Asked Questions

Does adding a sleep always fix the error?

No. A delay can change timing without correcting a close race, an unresolved promise, or a browser crash. The fix is to identify and order the operation that owns the target.

Can a website itself cause Target closed?

A page can trigger a Chromium crash or expose an environment problem, but the error still means the target disappeared before CDP completed its command. Use stderr and a minimal reproduction to distinguish page-specific crashes from application cleanup.

Should I close the page or the browser after a failed screenshot?

Finish or abandon all operations using the page, close the page, then close its browser. If Chromium has already disconnected, collect diagnostics and let the failed browser job terminate before starting a clean one.

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

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.