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

The fastest reliable approach is to remove avoidable startup work, not to tweak a single Puppeteer flag. Deploy a Chromium build that is compatible with Lambda, match its release to your Puppeteer version, give the function enough memory, keep Chrome’s profile and cache on writable /tmp, and measure cold and warm invocations separately. If first-use extraction or download dominates, use the chromium-min packaging model and reuse files in a warm execution environment. These changes improve the parts you can control, but no source establishes a universal percentage speedup; your page, architecture, runtime and memory setting determine the result.

What actually makes a Lambda Puppeteer launch slow?

A Lambda browser invocation has several timings that are often collapsed into one number:

  • Function initialization, including loading your JavaScript modules.
  • Resolving, downloading or extracting the Chromium executable and its libraries.
  • The puppeteer.launch() call itself.
  • Page readiness for the real job, such as navigation, JavaScript rendering, PDF generation or screenshot capture.

A warm invocation may reuse an execution environment and files in /tmp; a cold invocation cannot. AWS documents these as different lifecycle conditions, so record them separately rather than advertising one “launch time.”

1. Start with a Lambda-compatible browser and a measured baseline

Use puppeteer-core with a compatible Chromium package

A normal desktop Puppeteer installation downloads a browser that is not automatically suitable for Lambda’s operating system and deployment constraints. Puppeteer’s troubleshooting guidance identifies Lambda package size as a challenge and points to the Sparticuz Chromium project as a workaround. The current @sparticuz/chromium README provides the launch arguments and executable-path pattern you should follow.

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

Record these values with every test:

  • Node.js runtime and Lambda architecture (x64 or arm64).
  • Puppeteer and Chromium package versions.
  • Configured memory and temporary-storage size.
  • Whether the invocation was cold or warm.
  • Initialization duration, executable resolution or extraction time, puppeteer.launch() duration, and time until the page is ready.

Do not treat “Chromium launched” as the complete user-facing metric. A browser that launches quickly but spends a long time loading the target page has not improved the end-to-end job.

Baseline launch example

Install puppeteer-core and the Chromium package version recommended for your Puppeteer release. Then use the package’s serverless settings rather than inventing a desktop configuration:

const puppeteer = require('puppeteer-core');
const chromium = require('@sparticuz/chromium');

exports.handler = async () => {
  const browser = await puppeteer.launch({
    args: chromium.args,
    defaultViewport: chromium.defaultViewport,
    executablePath: await chromium.executablePath(),
    headless: chromium.headless
  });

  try {
    const page = await browser.newPage();
    await page.goto('https://example.com', {waitUntil: 'networkidle2'});
    return {statusCode: 200, body: await page.title()};
  } finally {
    await browser.close();
  }
};

The exact supported Chromium release matters. Sparticuz recommends matching its Chromium version to the version supported by your Puppeteer release. Verify the pairing whenever either dependency changes.

2. Tune memory using your real workload

Sparticuz maintainer guidance says: “You should allocate at least 512 MB of RAM to your instance; however, 1600 MB (or more) is recommended.” This is a recommendation, not a benchmark guarantee for every Lambda function.

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

Run the same representative URL, PDF, or screenshot workload at several memory settings. Compare:

  • Initialization and launch duration.
  • Time to complete the actual page task.
  • Timeouts, crashes and out-of-memory symptoms.
  • The resulting Lambda cost for the complete invocation.

Choose the setting that gives your workload an acceptable end-to-end result. Do not assume that the maintainer’s 1600 MB recommendation is universally optimal, and do not claim a fixed percentage improvement without your own controlled measurements.

3. Avoid repeated download and extraction work

When the regular package is appropriate

The standard @sparticuz/chromium package includes the binaries needed by its supported deployment targets. It is straightforward, but the browser and libraries contribute to your deployment package size. Keep the package and its version fixed while you establish a baseline so that packaging changes do not get confused with memory changes.

When to consider chromium-min

@sparticuz/chromium-min omits the Brotli binaries and lets your function obtain a separate Chromium pack. The maintainer documents a flow in which a remote pack is downloaded and unpacked to /tmp/chromium-pack, then Chromium is decompressed to /tmp/chromium. On later invocations in the same warm environment, existing files are detected and reused.

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.

This can avoid repeating download or extraction work when an environment is reused, but it does not promise a particular launch-time improvement. A cold start still has to retrieve and unpack the pack. Treat /tmp reuse as opportunistic: Lambda may discard the environment at any time.

Follow the current README’s remote-pack example rather than copying an old snippet. Confirm that the pack location is reachable from the function, that the extracted files fit in temporary storage, and that your deployment policy permits the required network access.

4. Put Chrome’s runtime files on writable storage

Chrome writes profile, configuration and cache files during startup. Lambda containers can have read-only areas, so a browser may fail or appear slow while retrying file operations if these paths are not writable.

Use /tmp for configuration, cache and user data

Set the XDG configuration and cache locations under /tmp when your runtime needs explicit paths, and use a writable user-data directory for the browser profile. For example, configure these environment variables before launching:

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.
process.env.XDG_CONFIG_HOME = '/tmp/chrome-config';
process.env.XDG_CACHE_HOME = '/tmp/chrome-cache';

Create any application-specific profile directory under /tmp as well. Leave enough temporary space for the downloaded or extracted browser, shared libraries, profile data and the output file. If a large page or PDF fills the available temporary storage, the resulting failure can look like a browser launch problem.

5. Match architecture, runtime and packaging

x64 and arm64 artifacts

The Sparticuz npm package contains x64 binaries. For arm64, its README documents artifacts beginning with Chromium v135 as either a Lambda layer ZIP or a remote pack used with chromium-min. Select an artifact that matches the architecture configured for the function; an architecture mismatch cannot be fixed with launch flags.

Version compatibility is a deployment requirement

Check the Puppeteer-supported Chromium revision and select the corresponding Sparticuz release. The package does not follow semantic versioning, and the maintainer warns that breaking changes can occur at patch level. Read the release notes and retest launches whenever you upgrade.

Keep bundlers from hiding browser files

If you use a bundler, mark @sparticuz/chromium as external. The README warns that bundling can break the relative paths the package uses to locate its binary files. Inspect the deployed artifact, not only your local bundle, and verify that the executable and supporting libraries are present where the package expects them.

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

6. Measure cold and warm launches reproducibly

Use structured timing logs around each phase. This small helper separates launch work from navigation:

const t0 = Date.now();
const browser = await puppeteer.launch({
  args: chromium.args,
  defaultViewport: chromium.defaultViewport,
  executablePath: await chromium.executablePath(),
  headless: chromium.headless
});
const launchedAt = Date.now();
const page = await browser.newPage();
await page.goto('https://example.com', {waitUntil: 'networkidle2'});
const readyAt = Date.now();
console.log(JSON.stringify({
  launchMs: launchedAt - t0,
  pageReadyMs: readyAt - launchedAt,
  totalMs: readyAt - t0
}));
await browser.close();

Invoke the function repeatedly after a deployment to collect cold and warm samples separately. Change one variable at a time—memory, package model, architecture or version—and keep the target URL and page workload constant. Report the distribution you observe rather than a single best run.

7. Troubleshooting slow or failed launches

“Failed to launch the browser process”

Check that the executable exists at the path returned by await chromium.executablePath(), that the Chromium artifact matches x64 or arm64, and that the package version is compatible with Puppeteer. If a bundler was used, mark the package external and inspect the deployed files.

Launch works locally but not in Lambda

Local desktop Chromium is not proof of Lambda compatibility. Use puppeteer-core with the Lambda-oriented package and its documented args, headless setting and executable-path call. Confirm the Node.js runtime and architecture used by the deployed function.

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

Permission, profile or cache errors

Move XDG configuration, cache and user-data paths to writable /tmp locations. Also verify that temporary storage is large enough for extraction, browser libraries, profile files and output.

Cold starts are much slower than warm starts

This is expected when initialization includes downloading or extracting Chromium. Measure those phases explicitly. The chromium-min remote-pack model can reuse extracted files in a warm environment, but it cannot eliminate cold-start work and Lambda can replace the environment.

Timeouts or intermittent failures after increasing memory

Re-test with the actual page and output size. More memory is a tuning variable, not a guarantee. Check navigation waits, temporary-storage consumption, network access to a remote pack and whether the page itself is waiting on resources.

An upgrade suddenly breaks deployment

Because Sparticuz does not use semantic versioning, even a patch-level update may contain breaking changes. Pin known-good versions, read release notes, verify the Puppeteer/Chromium pairing and repeat both cold and warm tests before promotion.

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

8. Cost and reliability decisions

Memory, duration and package strategy interact. A higher memory setting may shorten a workload while changing its per-invocation price; a remote pack may reduce deployment-package pressure while adding cold retrieval and network dependencies. Compare total cost and completion time for the same workload instead of optimizing launch milliseconds in isolation.

For reliability, keep a fallback plan for remote-pack retrieval, monitor extraction and launch errors separately, and make browser cleanup unconditional with try/finally. Do not depend on a warm /tmp directory for correctness; use it only as a cache.

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 your goal is a clean website screenshot rather than managing Chromium inside Lambda, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP or PDF. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled.

Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers. An MCP server supplies take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

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

See the ScreenshotNeo API documentation for all options. A minimal call is:

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

It supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets and custom viewports, retina scale, PDF paper size/margins/landscape/page ranges, HTML/CSS-to-image, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for selectors/delays/network idle, request and resource blocking, custom headers/cookies/user agents/Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed public image links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.

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)

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}`);

The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it without managing a Lambda browser.

Frequently Asked Questions

Should I use full Puppeteer or puppeteer-core in Lambda?

Use puppeteer-core with a Chromium distribution intended for Lambda, then follow that distribution’s documented launch configuration and version pairing.

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

Does raising Lambda memory always make Chromium launch faster?

No. Memory is a workload-dependent tuning variable. Test several settings and compare complete duration, failures and cost for your real page or PDF task.

Can a warm /tmp cache remove cold starts?

No. It can let a reused environment skip work such as extraction, but Lambda may create a new environment that must perform initialization again.

What should I verify before switching a function to arm64?

Verify that the selected Chromium artifact supports arm64, that the Node.js runtime and Puppeteer release are compatible, and that the deployed package or layer matches the function architecture.

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.

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