ScreenshotNeo

BlogHow-to

How to Run Puppeteer in an Azure Function

Deploy Puppeteer in Azure Functions by matching the Node.js runtime, browser binary, Linux libraries, and hosting plan. Includes runnable code and troubleshooting.

By the ScreenshotNeo team4 October 202610 min read

Direct answer: To run Puppeteer in an Azure Function, deploy a Node.js function together with a compatible browser executable and the operating-system libraries that browser needs. Configure Puppeteer to find that executable, then verify the complete deployment in the Azure hosting plan and operating system you will use. A browser that works on your workstation may fail after deployment because its binary, architecture, shared libraries, filesystem permissions, or runtime differ.

For a new serverless Function App, Microsoft recommends Flex Consumption. It is Linux-only, so check Puppeteer’s current Linux and architecture requirements before choosing it. Other hosting plans have different deployment and package behaviors; there is no single browser path or launch flag that works across all Azure Functions environments.

1. Choose the Azure hosting and deployment model

Choose the plan and operating system before assembling the deployment artifact. The browser and its dependencies must match the environment that executes the function.

Hosting option What to account for
Flex Consumption Linux-only, with managed package deployment and package execution built in. Microsoft recommends it for new serverless Function Apps.
Legacy Consumption Windows and Linux deployment behavior differs. Linux Consumption uses plan-specific remote-build or external-package procedures. It is on a retirement path.
Elastic Premium or Dedicated ZIP and Linux container deployment are supported under documented conditions. A container can make the browser and system libraries explicit.
Azure Container Apps Functions use container-image deployment rather than the ZIP code-package deployment model.

Read Microsoft’s current [deployment options by hosting plan](https://learn.microsoft.com/azure/azure-functions/functions-deployment-technologies) and [package deployment guidance](https://learn.microsoft.com/azure/azure-functions/run-functions-from-deployment-package) before setting deployment app settings. Do not copy WEBSITE_RUN_FROM_PACKAGE values from one plan to another without checking the plan-specific instructions.

Package deployment has a 1 GB maximum package size, and Consumption provides 500 MB of temporary storage per plan. Running from a package makes wwwroot read-only. Keep any browser-required temporary files in a writable location and make sure the browser artifact fits the applicable package and storage limits. See Microsoft’s [package deployment limits and behavior](https://learn.microsoft.com/azure/azure-functions/run-functions-from-deployment-package).

Linux Consumption Functions v3 stop on 30 September 2026, and Linux Consumption hosting is planned to retire on 30 September 2028. Avoid making a new implementation depend on a retiring plan without a migration plan. See Microsoft’s [Azure Functions operating system and runtime support guidance](https://learn.microsoft.com/azure/azure-functions/functions-versions).

2. Match Node.js, Puppeteer, and the browser

Puppeteer is the Node.js automation library; the browser is a separate deployment concern. The current Puppeteer system requirements specify Node.js 22.12 or later and Chrome for Testing on Debian/Ubuntu and openSUSE/Fedora Linux for x64 and arm64. Check the current [Puppeteer system requirements](https://pptr.dev/guides/system-requirements) and Microsoft’s [Azure Functions Node.js reference](https://learn.microsoft.com/azure/azure-functions/functions-reference-node) when selecting the runtime, build environment, and architecture.

  • puppeteer normally downloads a compatible Chrome for Testing browser during installation. The download must be included and accessible in the deployed environment. Puppeteer documents a Linux Chrome download of approximately 282 MB, so account for the artifact’s size.
  • puppeteer-core does not download a browser. Use it when you provide a browser separately or connect to a remote browser, and configure the actual executable path or supported connection.
  • If your package manager disables install scripts, the browser download may be skipped. Explicitly install the matching browser during the build or deployment process, following Puppeteer’s [installation guide](https://pptr.dev/guides/installation).

Keep Puppeteer and Chrome for Testing compatible. If you supply another browser binary, verify it against the deployed Puppeteer version; the documentation does not certify arbitrary Azure-provided browser binaries.

3. Add the function and Puppeteer dependency

The following is a minimal Azure Functions Node.js v4 programming model example. It accepts a query parameter named url, navigates to that address, and returns a PNG. It assumes your deployment process has included the Puppeteer browser and all required Linux libraries. Create the function using the current [Azure Functions Node.js developer guide](https://learn.microsoft.com/azure/azure-functions/functions-reference-node) and install Puppeteer in the function app project:

npm install puppeteer

Example src/functions/screenshot.js:

const { app } = require('@azure/functions');
const puppeteer = require('puppeteer');

app.http('screenshot', {
  methods: ['GET'],
  authLevel: 'function',
  handler: async (request, context) => {
    const target = request.query.get('url');
    if (!target) {
      return { status: 400, jsonBody: { error: 'Pass a url query parameter.' } };
    }

    let parsed;
    try {
      parsed = new URL(target);
    } catch {
      return { status: 400, jsonBody: { error: 'The url must be a valid absolute URL.' } };
    }
    if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
      return { status: 400, jsonBody: { error: 'Only http and https URLs are supported.' } };
    }

    let browser;
    try {
      browser = await puppeteer.launch({
        headless: true,
        // If using puppeteer-core or a separately supplied browser, set
        // executablePath to the actual path in your deployed environment.
        // Do not assume a path from another image or hosting plan.
      });
      const page = await browser.newPage();
      await page.setViewport({ width: 1280, height: 800 });
      await page.goto(parsed.href, {
        waitUntil: 'networkidle2',
        timeout: 45000,
      });
      const png = await page.screenshot({ type: 'png', fullPage: true });
      return {
        status: 200,
        headers: { 'Content-Type': 'image/png', 'Cache-Control': 'no-store' },
        body: Buffer.from(png),
      };
    } catch (error) {
      context.error('Screenshot capture failed', error);
      return { status: 502, jsonBody: { error: 'The page could not be captured.' } };
    } finally {
      if (browser) await browser.close().catch((error) => context.error('Browser close failed', error));
    }
  },
});

Install the Azure Functions package used by the v4 model if your starter project does not already include it:

npm install @azure/functions

The example validates basic URL syntax and protocol, but a public screenshot endpoint also needs an explicit destination policy. Otherwise callers may try to reach internal services or cloud metadata endpoints. Restrict allowed hosts or IP ranges, account for redirects, and apply appropriate authentication and rate limits for your application.

4. Include the browser and Linux libraries

With puppeteer, run installation in a build environment compatible with the target runtime and architecture so its downloaded browser is present in the published artifact. With puppeteer-core, supply a browser yourself and set executablePath to its actual deployed path:

const puppeteer = require('puppeteer-core');
const browser = await puppeteer.launch({
  headless: true,
  executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
});

Set PUPPETEER_EXECUTABLE_PATH in the Function App configuration to the path verified in that deployment. Do not assume the path is identical across local development, a managed Azure image, and a custom container.

A browser file can exist and still fail to launch because Linux shared libraries are missing. Puppeteer’s [Linux troubleshooting guide](https://pptr.dev/troubleshooting) lists common Debian dependencies. In an environment where you can inspect the browser binary, use ldd /path/to/chrome to identify unresolved shared libraries. Add the required packages to the supported build image or container, then redeploy.

Do not add --no-sandbox by default. The reviewed Azure and Puppeteer guidance does not establish that it is universally required or safe for Azure Functions. Check the actual runtime’s permissions and browser error output, then choose launch settings for that environment.

5. Deploy and verify in Azure

  1. Choose the Function App plan, operating system, Node.js runtime, and architecture.
  2. Build or install dependencies in an environment compatible with that target. Confirm that browser installation scripts ran, or explicitly install the browser if scripts are disabled.
  3. Use the deployment method supported by the plan. For containers, include the browser and libraries in the image. For package deployment, follow that plan’s build and package execution steps.
  4. Configure any browser executable path through the Function App’s application settings. Keep wwwroot read-only assumptions and temporary storage limits in mind.
  5. Deploy a small test function and inspect its logs. Confirm that the browser launches, the page loads, and a screenshot is returned under the deployed identity and permissions.
  6. Exercise slow pages, redirects, large pages, repeated invocations, and concurrent calls. Tune timeouts, memory, and concurrency based on the selected plan and workload.

6. Tune reliability, performance, and cost

Reuse resources carefully

Launching a browser for every request is simple and isolates failures, but browser startup adds work to each invocation. Reusing a browser across warm invocations may reduce repeated startup overhead, but requires lifecycle handling: detect disconnected browsers, avoid leaking pages, limit concurrent work, and expect process recycling. Do not assume a warm instance remains alive between invocations.

Bound the work

  • Set a navigation timeout appropriate to your function’s execution limit and the pages you capture.
  • Prefer a deliberate readiness condition when a site never becomes network-idle because of analytics, streaming, or polling.
  • Close pages and browsers in a finally path, as in the example, and log enough context to diagnose navigation and launch failures without exposing secrets.
  • Limit simultaneous browser pages. Browser memory use can grow with page complexity and concurrency.
  • Use a custom container when you need to control the OS libraries and browser installation, provided the selected Azure hosting option supports that deployment model.

Budget for artifacts and execution

The Linux Chrome for Testing download is approximately 282 MB according to Puppeteer’s installation documentation. Azure Functions package deployment has a 1 GB maximum package size, and Consumption provides 500 MB temporary storage per plan. These are documented limits, not performance measurements. Browser startup time, capture duration, memory, and Azure charges depend on the application, page, region, plan, and concurrency; measure your workload and consult current Azure pricing rather than assuming a universal cost per screenshot.

Package execution can improve loading and cold-start behavior, particularly for JavaScript apps with large npm dependency trees, but it does not remove browser compatibility, library, or writable temporary path requirements. See Microsoft’s [package deployment documentation](https://learn.microsoft.com/azure/azure-functions/run-functions-from-deployment-package).

7. Troubleshoot common failures

Symptom Likely cause What to check or fix
“Could not find Chrome” or browser executable missing Puppeteer’s install script did not run, the browser was not included in the deployment, or puppeteer-core has no configured browser. Check the installed package and deployed browser files. Enable the intended install step or explicitly install a compatible browser. For puppeteer-core, set the real executable path.
Chrome exists but does not launch on Linux Missing shared libraries, architecture mismatch, file permissions, or runtime incompatibility. Confirm x64/arm64 alignment and executable permissions. Inspect unresolved dependencies with ldd and follow Puppeteer’s Linux troubleshooting guide.
Works locally, fails after deployment Local and Azure environments differ in OS, Node version, architecture, package build, or filesystem access. Build for the target environment, verify the deployed runtime and browser path, and inspect Azure invocation logs.
Function returns a timeout The navigation or capture exceeds a function or page timeout; the page may keep network activity open. Use a realistic navigation timeout and readiness condition. Check the selected plan’s execution limits and avoid waiting for network idle when the site never settles.
Permission denied or cannot write a file The package-backed wwwroot is read-only, or the chosen temporary path is not writable. Write only to a verified writable temporary location, or return the screenshot buffer directly as in the example.
Package deployment fails or artifact is too large Browser plus dependencies exceed package limits, or a plan-specific deployment procedure was used. Check the 1 GB ZIP limit, reduce unnecessary files, or use a supported container deployment. Follow the current deployment instructions for the plan.
Intermittent failures under load Too many concurrent browser pages, process recycling, memory pressure, or unclosed resources. Cap concurrency, close pages and browsers reliably, monitor logs and resource use, then adjust plan capacity based on measurements.

Or skip the browser setup

If you need website screenshots without packaging Chrome into an Azure Function, ScreenshotNeo provides a screenshot API and MCP server. Its one-call API returns a screenshot or PDF, with parameters for common capture needs. See the ScreenshotNeo API documentation.

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 accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup 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 take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

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

FAQ

Should I use puppeteer or puppeteer-core?

Use puppeteer when its downloaded compatible browser is part of your deployment. Use puppeteer-core when you provide the browser separately or connect remotely; it does not download a browser for you.

Is Flex Consumption suitable for Puppeteer?

It can be, if your Node.js runtime, Linux browser artifact, shared libraries, package size, and workload fit the plan. Flex Consumption is Linux-only and Microsoft’s recommended plan for new serverless Function Apps; validate your browser deployment in it.

Does Puppeteer always need --no-sandbox in Azure?

No universal Azure Functions requirement is established by the reviewed documentation. Diagnose the actual launch error and runtime permissions before changing sandbox settings.

Can I use a remote browser instead of shipping Chrome?

puppeteer-core can be used with a separately supplied browser or remote browser connection. The connection details and compatibility are specific to the browser service you choose.