Recommended Free Tools
You can run a Puppeteer screenshot script in Google Cloud Functions by deploying a Node.js HTTP function with Puppeteer installed, a browser cache that survives the build, and enough time and memory for the pages you capture. Google’s current function documentation uses the Cloud Run functions name; the example below targets the newer Cloud Run functions generation. Check the current runtime and deployment guidance before choosing a runtime or adapting the command for first-generation functions.
What you will deploy
This example exposes an HTTP endpoint that accepts a URL, captures a PNG with Puppeteer, and returns the image bytes in the HTTP response. It validates the URL and closes the browser after capture, including on errors. Returning bytes is convenient for small, synchronous captures; for larger results or work that should continue after the request returns, store the image and return a reference instead.
As an Amazon Associate I earn from qualifying purchases.
Cloud Functions is still a familiar name for this workflow, but Google’s current documentation brands the newer product Cloud Run functions. The two generations do not share every runtime and deployment limit, so do not assume a first-generation command or ceiling applies to a newer function. See Google’s function deployment documentation and select the generation that matches your project.
Prepare the project and browser cache
Check your runtime
Choose a Node.js runtime supported by the generation you plan to deploy, and verify its lifecycle in Google’s runtime support table before deployment. The currently consulted table lists Node.js 24 for Run functions and Node.js 22 for both first-generation and Run functions; those entries and their support dates can change.
#1 Best Overall
Create the files
The following project uses the Functions Framework to expose an HTTP handler and Puppeteer to install and manage a compatible Chrome for Testing browser. The exact dependency versions are deliberately not pinned here: choose versions under your project’s reproducibility policy, commit a lockfile, and confirm the Puppeteer/browser pairing you deploy.
mkdir puppeteer-shot
cd puppeteer-shot
npm init -y
npm install @google-cloud/functions-framework puppeteer
In package.json, ensure the start script invokes the framework. Keep the dependencies written by npm and add or merge this script:
{
"scripts": {
"start": "functions-framework --target=screenshot --signature-type=http"
}
}
Create .puppeteerrc.js in the project root:
module.exports = {
cacheDirectory: './node_modules/.puppeteer_cache',
};
Puppeteer documents this cache location for Google Cloud Functions because a build that reuses cached node_modules may not rerun the browser installation step. Confirm that your chosen build pipeline installs or preserves the browser at that location; a configuration file cannot compensate for a browser binary that was never installed or was discarded.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesImplement the HTTP screenshot handler
Create index.js. This handler allows only HTTP and HTTPS URLs and rejects credentials embedded in the URL. That is basic input validation, not a complete defense for a public screenshot endpoint: an unrestricted URL-taking service can be abused to request internal network addresses or consume resources. Apply an explicit SSRF policy, authentication, quotas, and any destination restrictions your use case requires.
const puppeteer = require('puppeteer');
exports.screenshot = async (req, res) => {
const rawUrl = req.query.url || (req.body && req.body.url);
let target;
try {
target = new URL(rawUrl);
} catch {
return res.status(400).json({ error: 'Provide a valid URL.' });
}
if (!['http:', 'https:'].includes(target.protocol) || target.username || target.password) {
return res.status(400).json({ error: 'Only credential-free HTTP and HTTPS URLs are allowed.' });
}
let browser;
try {
browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto(target.href, { waitUntil: 'networkidle2', timeout: 45000 });
const image = await page.screenshot({ type: 'png', fullPage: true });
res.set('Content-Type', 'image/png');
res.set('Cache-Control', 'no-store');
return res.status(200).send(image);
} catch (error) {
console.error('Screenshot capture failed:', error);
return res.status(502).json({ error: 'The page could not be captured.' });
} finally {
if (browser) {
try {
await browser.close();
} catch (error) {
console.error('Could not close Puppeteer browser:', error);
}
}
}
};
networkidle2 is an example wait condition, not a universal choice. Some sites keep network connections open or load important content later; others never become meaningfully idle. Use the condition, selector wait, or delay that fits your target pages, and set navigation and function timeouts accordingly. The PNG is held in memory and sent synchronously here, so this pattern is best for modest image responses.
Deploy the function
- Enable the needed Google Cloud services and select your project. Use the Google Cloud Console or CLI according to your environment, and authenticate the
gcloudCLI if using the command below. - Deploy from the project directory. Set a supported runtime, region, HTTP trigger, entry point matching
exports.screenshot, and resource limits. Replace the example region and runtime with values appropriate to your project and current support status:gcloud functions deploy puppeteer-shot --gen2 --runtime=nodejs24 --region=us-central1 --source=. --entry-point=screenshot --trigger-http --memory=1Gi --timeout=120s - Choose who can invoke it. The example trigger does not by itself decide your intended access policy. For a private endpoint, configure authentication and grant invocation access only to the required principals. If you permit unauthenticated access, add abuse controls and URL restrictions before exposing it publicly.
- Wait for deployment and test a representative page. Use the deployed function URL with an encoded URL parameter, for example
?url=https%3A%2F%2Fexample.com. Confirm the response hasContent-Type: image/pngand that the returned image is complete.
Google’s gcloud functions deploy reference documents deployment options including runtime, region, source, entry point, trigger, memory, and timeout. Its documented default timeout for a new function is 60 seconds; it also documents a 540-second maximum for first-generation functions. Those figures are generation-specific configuration facts, not a recommended setting for every screenshot workload. Set limits based on browser startup, page load, capture time, and observed resource use.
Choose how the screenshot leaves the function
Return image bytes
The sample returns PNG bytes directly, which keeps the integration simple when the caller needs an immediate, moderate-sized result. The caller must be prepared to read a binary response rather than JSON. A large full-page screenshot can make a synchronous response and in-memory handling less suitable.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Persist the image and return a reference
For larger captures, retries, or processing that can outlive an HTTP request, save the image to a storage service and return a reference or status. Decide the storage location, access controls, retention, and whether the reference is public or signed; there is no single output destination implied by using Cloud Functions.
Best Value
Generation, package, and resource choices
puppeteer or puppeteer-core
| Package | Browser handling | When it fits |
|---|---|---|
puppeteer |
Installs a compatible Chrome for Testing browser during package installation. | Use when you want Puppeteer to manage the matching browser binary. |
puppeteer-core |
Does not download Chrome; you must manage the executable path or connect to a supported browser yourself. | Use when you deliberately supply or manage the browser separately. |
For this guide’s conventional deployment, puppeteer is the simpler starting point. Switching to puppeteer-core does not remove the need for a compatible Chrome binary.
Memory and timeout
The sample’s 1Gi memory and 120s timeout are starting command values, not a tested minimum or universal recommendation. Browser launch, page complexity, image dimensions, and concurrency affect resource use and duration. Measure representative pages, monitor failures and execution time, and adjust. Google’s troubleshooting guidance notes that increased resources or a longer timeout can help when resource exhaustion contributes to startup failure; it does not establish a universal Puppeteer memory requirement.
Troubleshoot deployment and capture failures
“Could not find Chrome” or browser launch fails
- Check build logs to verify
puppeteerinstalled successfully and that its browser download was not skipped. - Confirm
.puppeteerrc.jsis at the project root and the build preservesnode_modules/.puppeteer_cache. - If the build uses cached dependencies, verify the browser binary exists in the deployed artifact; cached
node_modulescan mean the install hook did not run again. - If you chose
puppeteer-core, configure the actual supported executable or browser connection rather than expecting it to download Chrome.
Deployment succeeds but the function is not ready
- Inspect Cloud Build logs first for package and build failures.
- Then inspect Cloud Logging for startup errors, especially exceptions or long-running work at global scope.
- Verify the configured entry point exactly matches the exported function name,
screenshot. - Review Google’s function troubleshooting guide; startup health-check failures can result from initialization exceptions, crashes, or timeouts.
The handler returns an error or times out on some pages
- Confirm the request includes a valid HTTP or HTTPS URL and that the function can reach the destination.
- Distinguish a rejected input (400) from a failed navigation or capture (502) using the response and function logs.
- If navigation fails because the page never reaches the chosen wait condition, select a wait strategy that matches that page and set a realistic navigation timeout.
- If representative captures exceed the configured function timeout or exhaust memory, reduce the work per invocation, resize or avoid unnecessarily large full-page captures, or adjust resources based on observed behavior.
Or skip the browser setup
If you only need a screenshot endpoint, ScreenshotNeo accepts a single GET request and returns an image or PDF. For example, this cURL request writes a WebP screenshot of Stripe to a file:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallcurl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. Its capture flow removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are not billed. An MCP server lets AI agents use screenshot and PDF tools. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Learn about ScreenshotNeo or sign up free for 1,000 screenshots a month with no card.
Frequently Asked Questions
Can Google Cloud Functions run headless Chrome?
Yes. Puppeteer’s Cloud Functions guidance says the Node.js runtime includes the system packages needed to run Headless Chrome; you still need to package and locate Puppeteer’s browser correctly.
Why use puppeteer-core instead of puppeteer?
Use puppeteer-core when you manage the browser executable or connection separately. It does not download Chrome as the regular puppeteer package does.
Quick Recap
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.




