What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
A Firebase Functions timeout while Puppeteer opens a page can come from two separate deadlines: the function’s overall execution limit, or Puppeteer’s browser, navigation, or content-wait stage. First log the time spent in each stage and identify the exact error; then change the matching setting or fix the browser installation, version pair, resources, or page-readiness condition. Raising the wrong timeout will not fix the underlying failure.
Identify which timeout you are seeing
“Firebase Functions timeout Puppeteer” is a symptom, not a diagnosis. The deployed function can reach its overall deadline while Puppeteer is launching Chromium, navigating, waiting for a selector, or processing a result. Each stage can also fail on its own. Firebase’s function deadline and Puppeteer’s page-level timeouts are independent: changing one does not automatically change the other. Firebase documents the function runtime limits in its Manage functions guide; Puppeteer documents page navigation and wait behavior in its Page API.
Use the complete error text and timestamps to determine which clock expired. “Navigation timeout of 30000 ms exceeded” points to a Puppeteer navigation wait; it does not by itself mean Firebase’s function deadline was reached. “Timed out while trying to connect to the browser” points earlier, around browser startup or connection. A platform deadline in the function logs means the whole invocation ran out of time. A selector wait can expire after navigation succeeds if the expected content never appears.
Record the deployment details before changing code
- Function name and trigger type: HTTP/callable, scheduled/task queue, or another event-driven trigger.
- First- or second-generation Functions, Node.js runtime, and deployed Firebase Functions SDK version.
- Exact versions of
puppeteerorpuppeteer-core, and the Chromium package or executable used. - Full exception, stack trace, browser stderr where available, and deployed function logs.
- Elapsed milliseconds for launch, new-page creation, navigation, content waits, result processing, and response completion.
Those details matter because a fix for a missing Chromium executable is different from one for a slow site, and the correct runtime-option syntax depends on the Functions generation and SDK.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
Measure the slow stage in deployed logs
Add timestamped stage logs around the browser lifecycle. Use the same deployed target and configuration that fails; a local run or emulator result alone does not establish that the production package contains a discoverable browser. Avoid logging secrets, cookies, authorization headers, or sensitive page content.
const mark = (stage, startedAt) => {
console.log(JSON.stringify({
stage,
elapsedMs: Date.now() - startedAt,
at: new Date().toISOString(),
}));
};
const startedAt = Date.now();
let browser;
try {
console.log('puppeteer.launch:start');
browser = await puppeteer.launch();
mark('puppeteer.launch:done', startedAt);
const pageStartedAt = Date.now();
const page = await browser.newPage();
mark('browser.newPage:done', pageStartedAt);
const navStartedAt = Date.now();
await page.goto(targetUrl, {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
mark('page.goto:done', navStartedAt);
} catch (error) {
console.error('render failed', error);
throw error;
} finally {
if (browser) await browser.close();
}
This is an instrumentation pattern, not a universal launch recipe: the correct launch options depend on the deployed Chromium distribution and versions. Add a separate timed log around any selector or application-specific wait, then inspect the deployed logs to see the last completed stage. If the platform terminates the invocation abruptly, the last log can still narrow down where time was spent.
Set Firebase’s function deadline for the trigger
Configure the function-level deadline and memory in code, redeploy, and verify the deployed configuration. Firebase says code runtime options are the source of truth by default and can override settings made through other methods. Its documented maximum depends on trigger type: HTTP and callable functions can be configured up to 3,600 seconds (60 minutes); scheduled and task queue functions up to 1,800 seconds (30 minutes); and other event-driven functions up to 540 seconds (9 minutes). Check the Firebase guide and the specific function generation before applying a value.
For a second-generation Node.js HTTP function, the shape is:
Rank #2
const { onRequest } = require('firebase-functions/v2/https');
const puppeteer = require('puppeteer');
exports.renderPage = onRequest({
timeoutSeconds: 120,
memory: '1GiB',
}, async (request, response) => {
// Launch the browser, navigate, collect the result, then respond.
});
The 120-second timeout and 1 GiB memory value above are examples, not guaranteed recommendations. Set a measured deadline that leaves room for normal variation without exceeding the limit for the trigger. In first-generation Functions, Firebase documents the runWith({ timeoutSeconds, memory }) form; do not copy second-generation imports or configuration blindly into a first-generation function. See Firebase’s runtime-options documentation for the current syntax and supported values.
A larger deadline only helps if the job is legitimately taking longer than its current budget. It will not install a missing browser, repair an incompatible runtime/browser pair, or make a selector match. If browser work routinely exceeds the latency that makes sense for a synchronous HTTP request, consider an asynchronous task or background workflow that returns a job identifier; choose the trigger and response design to fit the application rather than treating a longer HTTP timeout as the only scaling option.
Check Chromium installation and executable discovery
If the error says “Could not find Chrome,” names a missing executable, or launch fails before navigation starts, inspect the deployed browser artifact before changing page timeouts. A successful package install does not necessarily prove that Chromium was downloaded, included in the deployment, or found at runtime.
Puppeteer’s troubleshooting guide has a Google Cloud Functions section. It recommends declaring Puppeteer as a dependency and placing its browser cache in a subdirectory of node_modules through Puppeteer’s configuration file. The reason is that Cloud Functions can cache node_modules between builds; when a dependency-install cache hit skips the install postscript, the browser cache may not be populated as expected.
Recommended Free Tools
Rank #3
- Check the build or deployment logs for the browser-install step and any cache hit.
- Inspect the Puppeteer configuration and confirm the cache directory is inside the deployed package as intended.
- Confirm that the expected executable exists in the deployed environment and that the code uses the correct path when required.
- Compare local and deployed package contents, Node.js version, and dependency versions rather than assuming they match.
Do not try to fix an executable-discovery error by raising page.goto()’s timeout: navigation has not started successfully yet.
Match Puppeteer, Chromium, and the deployed runtime
Record the exact versions deployed rather than relying on a broad instruction such as “use the latest Chromium.” Puppeteer and its browser build need a compatible pairing, and serverless Chromium packages can have their own release-specific setup. If using @sparticuz/chromium, follow the instructions for the actual package release, including its stated Puppeteer compatibility, executable-path flow, and cleanup guidance. Its project documentation directs users to select a Chromium version supported by Puppeteer’s Chromium support information.
Launch stalls can also indicate resource pressure or a runtime mismatch. Firebase allows memory to be configured and documents that second-generation CPU defaults vary with allocated memory. Chromium startup and complex pages can require more resources than ordinary request handling, but there is no single memory size that is reliable for every site and workload. Measure launch and navigation time in the deployed function, and examine logs for memory termination or other resource pressure before increasing limits without evidence.
Choose a page wait that matches the work
After launch succeeds, inspect the navigation and content waits separately. Puppeteer navigation options have their own timeout; so do selector or other wait operations. Set a finite bound for each important stage and report which one expired so that a later timeout is not mistaken for a slow navigation.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsRank #4
domcontentloadedcan be sufficient when the task needs the initial document markup.- A network-quiet condition can be a poor fit for pages with long-lived connections, polling, or persistent analytics requests.
- If the needed content renders asynchronously, wait for the specific selector or application condition that represents completion instead of waiting indefinitely for all network activity to stop.
For example, a page that must contain a result element can navigate first and then wait for that element with a separately chosen bound:
await page.goto(targetUrl, {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.waitForSelector('[data-render-complete="true"]', {
timeout: 10_000,
});
Those example limits are illustrative. Set them according to the site and task. If the selector times out, check that it exists in the deployed page, that the page returned the expected content, and that the application actually produces it under the deployed authentication and request conditions.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Close the browser on success and failure
Always put browser cleanup in a finally block and await browser.close(). This prevents a failed navigation or content wait from bypassing cleanup. The serverless Chromium project also explicitly advises closing the browser even when the script returns an error. If cleanup itself can fail in your environment, log that failure separately so it does not conceal the original navigation or launch exception.
let browser;
try {
browser = await puppeteer.launch(/* verified runtime-specific options */);
const page = await browser.newPage();
await page.goto(targetUrl, {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.waitForSelector('[data-render-complete="true"]', {
timeout: 10_000,
});
// Collect the result needed by the function.
} finally {
if (browser) await browser.close();
}
Use this as a lifecycle pattern, not as code guaranteed to run unchanged in every Firebase generation or Chromium setup. Set URL validation, authentication, launch flags, and response handling for the application and deployment.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Diagnose common Firebase Functions and Puppeteer timeout errors
| Symptom | First checks | Next action |
|---|---|---|
| Function logs show the configured deadline was reached | Trigger type, deployed timeout, and stage timestamps | If the work is legitimately slow, set the code-side deadline within that trigger’s documented maximum and profile the slow stage. Firebase |
Could not find Chrome or executable missing |
Deployed cache path, install/build logs, and package contents | Follow Puppeteer’s Cloud Functions cache guidance and verify the browser is installed and discoverable. Puppeteer |
| “Timed out while trying to connect to the browser” or launch stalls | Launch-stage timing, executable path, exact versions, and memory | Check the deployed runtime dependencies and supported browser pairing; measure launch separately. Sparticuz Chromium |
| “Navigation timeout of 30000 ms exceeded” | Time spent in page.goto(), selected waitUntil, and site network behavior |
Set an intentional navigation timeout and choose the least restrictive readiness condition that meets the task. Puppeteer Page API |
| A selector or content wait expires after navigation | Whether the expected content is produced and the selector matches the deployed page | Inspect the response and page condition, then wait for the actual application state with a finite bound. Puppeteer Page API |
| Puppeteer works locally but times out after deploying Firebase Functions | Build cache/install behavior, deployed Node/browser versions, runtime settings, and logs | Compare the deployed artifact and configuration with local versions; local or emulator success does not prove Chromium is available in production. Puppeteer troubleshooting |
Or skip the browser setup
If the goal is to capture a website rather than run a bespoke Puppeteer workflow inside Firebase, ScreenshotNeo provides a website screenshot API. A single GET request can return a screenshot or PDF. Its clean-shot steps can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. These are alternatives for capture work, not a repair for code that specifically requires your own Firebase-hosted browser session.
For API parameters and options, see the ScreenshotNeo documentation. This cURL example saves a WebP capture:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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}`);
ScreenshotNeo has a free plan with 1,000 screenshots per month and no card required; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card.
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.




