ScreenshotNeo

BlogHow-to

How to Close a Web Worker in Puppeteer

Close a Puppeteer WebWorker with worker.close(), find page workers safely, and choose the right cleanup scope when you need to shut down more than one worker.

By the ScreenshotNeo team4 October 20265 min read

To close a Puppeteer WebWorker, call await worker.close() on the worker instance. Find dedicated workers for a page with page.workers(); it does not include ServiceWorkers. If you only need to observe worker lifecycle, listen for workercreated and workerdestroyed on the page. Puppeteer exposes WebWorker.close(), but its API reference does not describe the method’s internal protocol behavior, so avoid assuming more than the documented call.

1. Close one WebWorker

Use an existing Puppeteer worker instance. This runnable Node.js example launches Chromium, opens a page, waits for workers to appear, closes each worker returned by page.workers(), then closes the browser:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');

    const workers = page.workers();
    console.log(`Found ${workers.length} dedicated worker(s)`);

    for (const worker of workers) {
      console.log('Closing worker:', worker.url());
      await worker.close();
    }
  } finally {
    await browser.close();
  }
})();

Install Puppeteer in a Node.js project with npm install puppeteer, save this as close-workers.js, then run node close-workers.js. The page may have no workers, or its workers may not exist yet at the time you inspect it. The loop safely handles an empty array.

For the individual-worker form, the essential code is simply:

await worker.close();

See the official Puppeteer WebWorker API for the method and the Page.workers() reference for its worker scope.

2. Track workers as they are created and destroyed

Register lifecycle listeners before navigation or before the page action that may create workers. These listeners report events; the destroy event is not a substitute for explicitly calling close() when your code owns the cleanup decision.

page.on('workercreated', worker => {
  console.log('Worker created:', worker.url());
});

page.on('workerdestroyed', worker => {
  console.log('Worker destroyed:', worker.url());
});

await page.goto('https://example.com');

for (const worker of page.workers()) {
  console.log('Current worker:', worker.url());
}

worker.url() helps identify which worker is being reported. page.workers() returns dedicated WebWorkers associated with that page and explicitly excludes ServiceWorkers. Do not treat this method as an inventory of every background worker associated with the browser.

3. Pick the cleanup scope you actually need

Closing a WebWorker targets a worker instance. Puppeteer also exposes broader cleanup methods; choose them when your actual goal is to close the surrounding resource:

Goal Call Documented scope
Close a WebWorker instance await worker.close() The API lists a close method on WebWorker.
Close one page await page.close() Closes the page. The method accepts optional { runBeforeUnload }.
Close a browser context await context.close() Closes that context and its associated pages. The default browser context cannot be closed.
Close the browser await browser.close() Closes the browser and its associated pages.
Detach Puppeteer await browser.disconnect() Disconnects Puppeteer while leaving the browser process running.

These methods have different documented scopes. Do not assume that closing a page, context, or browser has exactly the same lifecycle semantics as calling WebWorker.close() directly. Refer to the official references for Page.close(), BrowserContext.close(), Browser.close(), and Browser.disconnect().

4. Common errors and edge cases

  • page.workers() returns an empty array: no dedicated worker is currently associated with that page, or the worker has not started yet. Attach workercreated before the page action that creates it, then inspect again after the action.
  • You cannot find a ServiceWorker: this is expected; page.workers() excludes ServiceWorkers. The documented API in this guide does not provide a ServiceWorker through that array.
  • A worker disappears before cleanup: workers can have their own lifecycle. Use the page’s workerdestroyed event to observe that change, and avoid treating a previously collected array as a guarantee that every worker remains available indefinitely.
  • You want the browser process to keep running: browser.disconnect() detaches Puppeteer and leaves the process running; browser.close() closes the browser and associated pages.
  • You try to close the default browser context: Puppeteer documents that the default context cannot be closed. Close an eligible non-default context when that is your intended scope.
  • You need exact termination mechanics: the WebWorker API reference lists close() but does not explain its protocol-level effect. Keep behavior claims to what the API documents.

5. Performance, reliability, and cost

Worker cleanup has no separate Puppeteer usage charge described in the cited API references. Its practical cost is the time and resources associated with keeping the page or browser alive, which depends on your workload; the documentation here provides no benchmark. Await asynchronous close calls so cleanup completes before the surrounding job exits. Put browser-level cleanup in a finally block when your program owns the browser, so a failure earlier in the job does not skip that broader cleanup.

When you need to close just one worker, use the worker method. Closing a whole page or browser has a broader impact on the resources your automation may still need. For reliable diagnostics, log the worker URL and listen for lifecycle events; do not infer that an empty initial list means the page can never create a worker later.

6. Or skip the browser setup

If your goal is a website screenshot rather than custom worker lifecycle control, ScreenshotNeo is a website screenshot API and MCP server. It returns a screenshot or PDF from one GET request, without requiring you to launch and manage Puppeteer for the capture.

For example, save a WebP screenshot with cURL:

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

Equivalent Python:

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)

Equivalent Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Read the ScreenshotNeo API documentation for request parameters. Cookie banners are accepted and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server offers screenshot, page-info, and PDF tools to AI agents. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free 1,000 screenshots per month, with no card required.

7. FAQ

Can I close every dedicated worker on a page?

Yes. Iterate over the array returned by page.workers() and await close() for each worker. The array covers dedicated WebWorkers, not ServiceWorkers.

Does worker.close() close the page?

The API reference documents a close method on WebWorker, while Page has its own separate close method. Use the method matching the resource you intend to close.

Can I use this to stop a ServiceWorker?

Not by retrieving it from page.workers(); that method excludes ServiceWorkers.

Should I disconnect or close the browser?

Disconnect when Puppeteer should detach while the browser process remains running. Close the browser when the browser and its associated pages should close.