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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To limit Puppeteer’s memory use, keep only a measured number of pages active, close each page and any task-specific context when finished, and stop downloading resources your task does not need. Measure the complete browser process tree under your actual URL mix; there is no universal number of megabytes per page or official one-size-fits-all RAM cap.

Why Puppeteer memory use varies

Puppeteer controls a browser, and browser memory is not the same thing as Node.js heap usage. Chromium can run multiple processes, including renderer processes for pages. The amount of memory depends on the sites being loaded, the number of live pages and contexts, media and other resources, JavaScript activity, browser version, and how much work runs concurrently. A complex application page and a mostly static page should not be assumed to cost the same amount.

That is why a fixed claim such as “each Puppeteer page uses X MB” is not a reliable sizing rule. The useful target is operational: complete the intended work without exceeding the memory budget or causing unacceptable failures, while preserving the page behavior your task depends on.

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

Reduce live browser work first

Bound concurrency

Pages running at the same time create more renderer work and raise the memory floor. Use a queue or a fixed worker count rather than launching a new page for every URL without a limit. Start with a deliberately small number, observe peak memory and throughput, then adjust against your deployment’s actual limit. There is no universal concurrency value that fits every site or machine.

Concurrency exists at more than one level: your job runner may start multiple Node processes, and each process may create multiple pages. Count all of those when planning a limit. In its troubleshooting guidance, Puppeteer gives jest --maxWorkers=2 as an example of restricting test-worker concurrency; that is an example, not a general Puppeteer page-count recommendation.

Close pages and contexts deterministically

When a URL’s work is complete, call await page.close() in a finally block so errors do not leave pages open. If you created an isolated browser context for a task, close or dispose of it when that task ends. Closing a page does not help if your own arrays, event listeners, closures, or accumulated results still retain references to pages or large objects.

Retain only what the job needs

Extract the required fields, write or send the result, and release per-page data instead of collecting page objects or full page payloads indefinitely. A long-lived browser can be useful, but it should not also become an unbounded store of work state.

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

A bounded Puppeteer pattern

This runnable Node.js example uses one browser and a fixed number of workers. Each worker opens one page at a time, blocks images, fonts, and media, navigates to a URL, then closes the page even if navigation fails. Replace the example URLs and extraction placeholder with your job. The resource filter is intentionally conservative only in the sense that it leaves scripts and stylesheets enabled; even blocking the listed resource types can change a site’s layout or behavior.

import puppeteer from 'puppeteer';

const urls = [
  'https://example.com/',
  'https://example.org/',
];
const concurrency = 2; // Measure and tune for your workload and memory limit.

const browser = await puppeteer.launch({
  headless: 'shell', // Use only if this mode preserves the behavior you need.
});

try {
  let next = 0;

  async function worker() {
    while (true) {
      const index = next++;
      if (index >= urls.length) return;

      const page = await browser.newPage();
      try {
        await page.setRequestInterception(true);
        page.on('request', request => {
          const type = request.resourceType();
          if (['image', 'font', 'media'].includes(type)) {
            request.abort();
          } else {
            request.continue();
          }
        });

        await page.goto(urls[index], { waitUntil: 'domcontentloaded' });
        // Extract and persist only the data this task needs.
      } finally {
        await page.close();
      }
    }
  }

  await Promise.all(
    Array.from({ length: Math.min(concurrency, urls.length) }, () => worker())
  );
} finally {
  await browser.close();
}

Request interception has an important failure mode: intercepted requests remain stalled until your handler continues, responds to, or aborts each one. Make a decision for every request; do not enable interception and leave requests unresolved. If another listener or interception logic is added later, make sure the combined handlers still settle each request correctly.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Or skip the browser setup

If your task is simply to capture a website rather than interact with it or extract application-specific data, ScreenshotNeo offers a screenshot API and MCP server. A single GET request returns an image or PDF, without requiring you to manage a Puppeteer browser process. See the API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
  • Cookie and consent banners are accepted like a visitor, and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status.
  • An MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.

Sign up for 1,000 free screenshots a month, with no card required.

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

Choose browser mode and network filtering carefully

Use headless shell only when it is correct for the task

Puppeteer launches headless by default. Its headless guide describes headless: 'shell' as using chrome-headless-shell, which can be more performant for automation tasks that do not need the complete Chrome feature set. The same guidance warns that shell does not match regular Chrome behavior completely. Treat it as a workload-specific option: verify the pages, interactions, and rendering results you depend on before switching. If the task needs full Chrome behavior, keep the appropriate mode rather than trading correctness for a possible resource benefit.

Block only resources you can afford to lose

Images, fonts, video, advertising, and analytics may be irrelevant to a text-only extraction, but stylesheets and scripts may be essential. A site can use client-side rendering, authentication flows, layout-dependent selectors, or script-generated content. Blocking a resource can therefore reduce transferred work while also breaking navigation, extraction, or visual output. Test a filter against representative pages and compare successful output, navigation time, failure rate, and memory—not just the number of requests blocked.

Keep stylesheets and scripts when the job needs rendered layout, client-side content, or application behavior. For a screenshot job, removing images is usually incompatible with the desired result. Resource filtering is a correctness decision as well as a memory and performance decision.

Reuse the browser, but set a recycling policy

Keeping a browser open across jobs avoids repeated startup overhead. For a long-running service or scraper, however, memory may not return to its initial level after pages close; site state, caches, extensions, or application-level references can contribute. Track process memory during representative runs. If memory continues to grow or stays above an operational threshold after work completes, recycle the browser at a threshold derived from your workload, or when a health check indicates it is needed.

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

Puppeteer’s official documentation does not specify a universal number of jobs, pages, or RSS value after which a browser should restart. Choose a threshold based on observed behavior and the limits of the machine or container where the process runs. Ensure your supervisor can restart the worker and that in-progress work can be retried or safely marked failed.

Measure the right memory and performance signals

Before tuning, run a representative mix of URLs at a known concurrency. Record parent and child-process RSS, live page and context counts, navigation duration, and failures. Repeat after changing one variable at a time—for example, concurrency, resource filtering, or headless mode. This helps distinguish a browser’s normal working set from unclosed pages or a workload that simply exceeds the available memory.

  • Memory reduction: Are there fewer simultaneous pages or fewer downloaded resources, and does peak process-tree RSS fall?
  • Correctness: Do extraction results, authentication, and rendering still work after a mode or resource change?
  • Throughput: At the same memory budget, how many URLs finish per minute?
  • Isolation: Does the task need separate contexts or browser processes, or can work safely share a browser?
  • Recovery: Can monitoring detect persistent RSS growth and recycle the browser without losing track of jobs?

Use RSS for browser process memory, not just the Node process’s heap statistics. Node’s heap limit concerns JavaScript objects managed by Node; it does not establish a cap on Chromium renderer memory. A low Node heap reading therefore does not prove that the browser is within its container memory budget.

Keep installation and container settings separate from RAM tuning

Puppeteer’s cacheDirectory, temporaryDirectory, and executablePath settings affect where browser files are stored or which executable is launched. Installation documentation says Puppeteer downloads Chrome for Testing and chrome-headless-shell and stores them in a cache directory by default. Those choices can solve disk, packaging, or deployment problems; they do not impose a renderer RAM ceiling. Browser download sizes are disk figures, not runtime memory measurements.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Likewise, do not assume a particular Chromium flag or Node heap setting universally lowers browser RSS. The Node heap and Chromium renderer are separate resource domains. Tune the process and container limits based on measured browser-process behavior, and avoid presenting unverified flags as a general memory fix.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot high memory use

Memory rises as more URLs run in parallel

Likely cause: Unbounded or unexpectedly layered concurrency means more pages or workers are active than intended. Fix: Add a queue or fixed worker pool, and count concurrency across both Node processes and pages. Increase the limit only after measuring peak RSS and failure rate.

Memory stays high after a URL finishes

Likely cause: A page was not closed on an error path, a context remains open, or application data still retains page-related references. Fix: Put page closure in finally, close task-specific contexts, and inspect collections, listeners, and closures that live beyond the task. Compare RSS before and after pages close over repeated runs rather than expecting an exact immediate return to startup memory.

Navigation hangs after enabling interception

Likely cause: A request handler failed to continue, respond to, or abort an intercepted request. Fix: Ensure every branch settles every request, including resource types not explicitly filtered. Temporarily disable interception to check whether it is involved, then restore it with a complete decision path.

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

Pages render incorrectly or extraction results disappear

Likely cause: A blocked resource or headless-shell behavior changed what the page loads or displays. Fix: Re-enable the resource types your task needs or use regular Chrome behavior. Validate against representative pages and the actual output you require, not only successful navigation.

Node heap looks healthy, but the container runs out of memory

Likely cause: Chromium child processes consume memory outside the Node heap. Fix: Monitor parent and child RSS together and size concurrency against the deployment’s total memory budget. Raising Node’s heap limit is not a substitute for managing renderer memory.

Changing browser cache paths does not reduce the peak

Likely cause: Cache or temporary-directory configuration addresses disk placement rather than live page memory. Fix: Check active pages, resource loading, browser mode, and process-tree RSS; use path settings for deployment and disk concerns only.

Does Puppeteer have a fixed RAM limit per page?

No workload-independent per-page figure or single RAM cap is established in Puppeteer’s documentation. Memory varies with the sites, browser work, and concurrency, so measure the process tree using the pages and deployment you actually run.

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

Does setting a Node.js heap limit cap Chromium memory?

No. The Node heap limit governs Node-managed JavaScript memory, while Chromium renderer processes use a separate memory domain. Monitor browser child processes as well as Node.

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.