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.

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

For most new deployments, the clearest route is a Lambda container image when you need to control the operating-system dependencies, or a Node.js function package using puppeteer-core with @sparticuz/chromium when you want a serverless Chromium package. In either case, deploy a matched Puppeteer–Chromium pair, verify it on the target Lambda architecture, and test the rendered output in Lambda itself.

Choose a deployment route

There are two practical ways to put browser automation on Lambda. A container image packages the runtime, browser, and operating-system libraries into one image. A function package can use puppeteer-core with a serverless Chromium distribution, optionally sharing browser files through a Lambda layer or delivering them separately.

Route Best fit Trade-offs to plan for
Lambda container image You want to control the operating-system environment or install browser dependencies alongside the application. Maintain the image and its browser dependencies; measure activation and cold-start behavior for your workload.
Function package plus Chromium layer You want to share browser dependencies among functions. Coordinate layer versions, function package versions, and architecture; manage package size.
chromium-min plus remote pack You need to keep browser binaries outside the main deployment package. Host and retrieve the separate files; account for network access and extraction in your operation and cold-start testing.

These are packaging trade-offs, not a speed or cost ranking. Neither route is universally fastest or cheapest; measure your own pages, traffic pattern, and deployment setup.

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

Check runtime, browser, and architecture compatibility

AWS’s current Node.js container-image documentation lists Node.js 26, 24, and 22 base images based on Amazon Linux 2023. Runtime availability changes, so confirm the current choices and lifecycle before selecting one in AWS’s Node.js Lambda container image documentation. AWS also supports OS-only and non-AWS base images; a non-AWS image must include the Lambda runtime interface client.

AWS’s Puppeteer container walkthrough dates to March 31, 2021, and uses Node.js 12. Treat it as an architectural example, not as a current Dockerfile or runtime template: Scaling Browser Automation with Puppeteer on AWS Lambda with Container Image Support.

Pin the Puppeteer–Chromium pair

With the package route, use puppeteer-core and explicitly provide Chromium. Do not assume that puppeteer-core supplies a browser binary. Check Puppeteer’s Chromium support information for the Puppeteer version you select, then use a compatible build of @sparticuz/chromium. The package’s version scheme follows Chromium rather than semantic versioning, and breaking changes can occur at patch level. Pin both dependencies, validate the pair, and inspect project release notes before upgrading. See the @sparticuz/chromium documentation.

Match the Lambda architecture

The regular npm package contains x64 binaries. For arm64, the project documents an alternative using @sparticuz/chromium-min with an arm64 layer zip or remote pack; its guide says arm64 artifacts are available starting with Chromium v135. Confirm the exact artifact and Lambda architecture agree. An x64 browser package is not interchangeable with an arm64 deployment. See the project’s architecture and packaging guidance.

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

Deploy with a function package and serverless Chromium

The following handler illustrates the launch pattern for the package route. It opens a page, navigates to a URL supplied in the event, and returns a PNG as base64-encoded response data. Pin tested versions of puppeteer-core and @sparticuz/chromium in your project rather than copying an unverified version pair.

  1. Install the packages. Add puppeteer-core and @sparticuz/chromium as production dependencies. If your deployment uses arm64, follow the arm64 package and artifact route instead.
  2. Create the handler. Use the Chromium-provided arguments and executable path; do not hard-code a local developer machine’s browser path.
  3. Package and deploy. Include the production dependencies or attach the matching layer, then configure the function’s architecture to match the browser binary.
  4. Invoke it in Lambda. Test with the actual runtime, page types, and network conditions your function will encounter.
const chromium = require('@sparticuz/chromium');
const puppeteer = require('puppeteer-core');

exports.handler = async (event) => {
  const url = event?.url;
  if (!url || typeof url !== 'string') {
    return { statusCode: 400, body: 'Provide a URL in event.url' };
  }

  let browser;
  try {
    browser = await puppeteer.launch({
      args: chromium.args,
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath(),
      headless: true,
    });

    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 });
    const image = await page.screenshot({ type: 'png' });

    return {
      statusCode: 200,
      headers: { 'content-type': 'image/png' },
      isBase64Encoded: true,
      body: image.toString('base64'),
    };
  } catch (error) {
    console.error('Browser capture failed', error);
    return { statusCode: 500, body: 'Browser capture failed' };
  } finally {
    if (browser) await browser.close();
  }
};

The example uses a 60-second navigation timeout, not a universal Lambda timeout recommendation. Set function timeout, memory, concurrency, and any storage configuration based on measured workload needs and current AWS limits. Pass URLs only from trusted callers or validate them against an allowlist: an endpoint that navigates to arbitrary user input can be abused to make requests to internal or otherwise unintended addresses.

Choose a navigation condition deliberately

networkidle2 waits for network activity to settle, which can suit many pages but may time out on sites with persistent requests. If the target site never becomes idle, choose a different navigation condition and wait for a meaningful selector or page state before capturing. A successful navigation event alone does not guarantee that client-rendered content, images, or fonts are ready.

Using a layer or the minimal package

Lambda layers can share browser dependencies across functions. The @sparticuz/chromium-min package omits the Brotli browser files, so those files must be supplied separately, for example through a layer or remote pack. The project says chromium.br is over 50 MB; that is a package-specific size statement, not an AWS deployment limit. Check the current AWS package and layer constraints for your deployment. Separate-file delivery adds hosting, retrieval, and extraction considerations that should be included in cold-start and failure testing.

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

Build and deploy a container image

Choose this route when packaging the browser libraries in a controlled OS image is more convenient than coordinating a function bundle and layers. AWS’s supported Node.js images provide a Lambda-compatible starting point. A typical build has these responsibilities:

  1. Select a currently supported AWS Lambda Node.js base image and the intended architecture.
  2. Install the application and the exact browser binary and operating-system libraries it requires.
  3. Set the image’s Lambda handler command according to the AWS base image instructions.
  4. Build for the same architecture configured for the function, publish the image to the registry required by Lambda, and create or update the function from that image.
  5. Invoke the deployed function and check browser launch, navigation, fonts, output, and logs in the Lambda environment.

The precise Dockerfile depends on the chosen base image and how you source Chromium. Do not lift the Node.js 12 Dockerfile from AWS’s 2021 example and treat it as current. Use the current base-image instructions and verify browser libraries in the final image; a successful build does not prove Chromium can launch at runtime.

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

Keep packaging and rendering reliable

Externalize Chromium in a bundler

If you build with esbuild, webpack, or another bundler, externalize @sparticuz/chromium. The package uses relative path resolution to locate browser files, and bundling it can break that lookup. Confirm the deployed artifact still contains or can access the expected files. The project documents this caveat in its README.

Provide fonts for the scripts you render

The Lambda runtime does not come with font faces. The Chromium project includes Open Sans with Latin, Greek, and Cyrillic coverage, but other scripts or brand-specific typefaces may need to be packaged and configured by you. Verify screenshots and PDFs in Lambda; missing glyphs and font substitutions can make output differ from a developer machine.

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

Measure performance and operating cost in context

Browser startup, page complexity, navigation waits, image and font loading, and whether a separate binary pack must be retrieved all affect execution. Compare approaches using representative pages and repeated invocations, including cold starts, failures, and peak concurrency. The available implementation guidance does not establish a universal memory setting, timeout, speed advantage, or cost winner, so use workload measurements rather than a generic number.

Troubleshoot common deployment failures

  • Executable path or browser launch fails: Ensure the function uses await chromium.executablePath(), the package files are present, and you pass chromium.args. Test the deployed artifact, not only the local build.
  • Architecture or executable-format error: Compare the Lambda architecture with the binary artifact. Use x64 binaries for x64; use the documented arm64 chromium-min plus matching arm64 layer or remote pack route for arm64.
  • Chromium cannot find its files after bundling: Externalize @sparticuz/chromium and ensure its relative file structure remains available at runtime.
  • Page navigation times out: Check whether the page keeps connections open, requires authentication, or is slow to render. A network-idle condition may never be reached on a page with persistent requests; select an appropriate wait strategy and make the function timeout reflect measured work.
  • Missing characters or substituted fonts: Include and configure fonts for the scripts and typefaces the output needs, then validate in Lambda.
  • Package or layer exceeds deployment constraints: Check current AWS size limits for the package and layers. Consider the documented minimal package with separately delivered files, while accounting for its retrieval and extraction path.
  • Upgrade breaks a previously working deployment: The Chromium package does not use semantic versioning. Pin known-good versions, test the exact pair, and review release notes before updating.

Or skip the browser setup

If the goal is simply to capture pages rather than operate Chrome in Lambda, ScreenshotNeo is a website screenshot API and MCP server. Its API returns an image or PDF from a single GET request. The following cURL example saves a WebP capture of Stripe; see the ScreenshotNeo documentation for API options and setup.

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

ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. 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 plan.

Frequently Asked Questions

Can I use Puppeteer’s full package instead of puppeteer-core?

The package-based route described here uses puppeteer-core and supplies Chromium separately. Choose the browser explicitly so the deployed binary and Puppeteer version can be checked as a pair.

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

Does the regular @sparticuz/chromium npm package support arm64 Lambda?

The project documents the regular npm package as containing x64 binaries. Its arm64 route uses @sparticuz/chromium-min with a matching arm64 layer zip or remote pack.

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.