PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, 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 minuteWait for a navigation boundary, then wait for the page state your image actually needs, and only then call page.screenshot(). A reliable baseline is page.goto(url, { waitUntil: 'networkidle2' }), followed by waitForSelector(), waitForFunction(), or a short waitForNetworkIdle() when content arrives after navigation.
The reliable Puppeteer sequence
This complete example waits for the main navigation to settle, verifies a page-specific element, captures a full-page PNG, and closes the browser even when an error occurs.
import puppeteer from 'puppeteer';
const url = 'https://example.com';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto(url, {
waitUntil: 'networkidle2',
timeout: 30_000,
});
// Replace this selector with an element that proves your page is ready.
await page.waitForSelector('body', {
visible: true,
timeout: 15_000,
});
await page.screenshot({
path: 'screenshot.png',
fullPage: true,
});
} finally {
await browser.close();
}
page.goto() resolves at the navigation boundary you choose. It does not promise that every image, font, animation, or client-side component is visually complete. The second wait should therefore represent the exact state that must appear in the screenshot. Always await page.screenshot(); otherwise your process can finish before the file is written.
Choosing waitUntil for navigation
The waitUntil value tells goto() which navigation event to observe. Pick the least expensive boundary that is sufficient for the page you are capturing.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
| Condition | What it observes | Use it when | Important limitation |
|---|---|---|---|
domcontentloaded |
The document has been parsed. | Your screenshot only needs the initial DOM and does not depend on images, fonts, or later resources. | Images, web fonts, and client-rendered data may still be missing. |
load |
The browser’s load event. |
The page treats the load event as its readiness boundary. | JavaScript can continue fetching and rendering after the event. |
networkidle2 |
Network activity has reduced to no more than a small number of active connections. | Most ordinary pages need their requests to settle. Puppeteer’s screenshot guide uses this condition. | Analytics, polling, streaming, or other persistent connections can keep the page changing. |
networkidle0 |
Zero in-flight network connections. | Only when the target genuinely becomes completely quiet. | Pages with long-lived connections may never reach it and will time out. |
For many sites, networkidle2 is a practical first attempt. If the page has a known readiness marker, combine a faster navigation boundary with a selector or predicate instead of waiting indefinitely for global network silence.
Waiting for requests that start after navigation
Single-page applications often begin data requests after goto() has resolved. Add the dedicated network-idle wait after navigation:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com/dashboard', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.waitForNetworkIdle({
idleTime: 500,
timeout: 10_000,
});
await page.screenshot({ path: 'dashboard.png' });
} finally {
await browser.close();
}
page.waitForNetworkIdle() resolves after the configured idle period and always waits at least that long. It is a traffic condition, not proof that the visual state you want exists. A page can be network-idle while a component still shows a skeleton, and a page with a WebSocket can remain non-idle forever.
Wait for the element that proves readiness
Use waitForSelector() for a visible component
If the screenshot must contain a report, chart, or confirmation panel, wait for that element directly:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesRank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
await page.goto('https://example.com/report', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.waitForSelector('[data-testid="report-ready"]', {
visible: true,
timeout: 15_000,
});
await page.screenshot({ path: 'report.png', fullPage: true });
Choose a selector that is emitted only when the required state is present. A generic body selector merely proves that a document exists; it does not prove that data, images, or a chart has rendered.
Use waitForFunction() for an application predicate
When readiness depends on text, a class, or a JavaScript value, wait for that predicate rather than guessing with a delay:
await page.goto('https://example.com/app', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.waitForFunction(
() => document.querySelector('[data-testid="status"]')?.textContent === 'Ready',
{ timeout: 15_000 },
);
await page.screenshot({ path: 'ready.png' });
This approach tracks the state that matters to the image. Keep the predicate deterministic and give it a timeout so a broken application produces an error instead of an endless wait.
Waiting for navigation caused by a click or form
Start the navigation wait before the action. Doing so prevents a fast navigation from occurring before Puppeteer begins listening for it.
Rank #3
await page.goto('https://example.com/list', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await Promise.all([
page.waitForNavigation({
waitUntil: 'networkidle2',
timeout: 30_000,
}),
page.click('a.next'),
]);
await page.waitForSelector('[data-testid="results"]', {
visible: true,
timeout: 15_000,
});
await page.screenshot({ path: 'next-page.png', fullPage: true });
The same pattern applies to a form submission. If the action updates the current document without a navigation, do not use waitForNavigation(); wait for the resulting selector or predicate instead.
Make the screenshot reflect the loaded page
Full page versus viewport
page.screenshot({ fullPage: true }) captures the document’s full scrollable height. Omit fullPage when you need only the current viewport. Set a viewport before navigation if layout breakpoints matter:
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'desktop.png', fullPage: true });
Lazy-loaded images
Network idle does not guarantee that content below the fold has been requested. A full-page capture can therefore contain unloaded lazy images. Wait for a page-specific “all images ready” condition when the site provides one, or trigger the site’s normal loading behavior before taking the screenshot. Do not assume a fixed sleep covers every image or font; rendering time varies with the page and environment.
Animations and changing content
A successful wait can still produce different pixels on each run if an animation, rotating banner, clock, or live feed is active. When reproducibility matters, use the application’s stable state or a predicate that identifies it. A timeout controls how long Puppeteer waits; it does not freeze the page after the wait succeeds.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Timeouts and failure handling
Set explicit timeouts for navigation and readiness waits. Catch failures and retain enough context to diagnose whether navigation, the selector, or the screenshot failed.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com/report', {
waitUntil: 'networkidle2',
timeout: 30_000,
});
await page.waitForSelector('[data-testid="report-ready"]', {
visible: true,
timeout: 15_000,
});
await page.screenshot({ path: 'report.png', fullPage: true });
} catch (error) {
console.error('Capture failed:', error);
// Save a diagnostic viewport when possible.
try {
await page.screenshot({ path: 'capture-error.png' });
} catch (diagnosticError) {
console.error('Diagnostic screenshot failed:', diagnosticError);
}
throw error;
} finally {
await browser.close();
}
Common symptoms and fixes
goto()times out withnetworkidle0: switch tonetworkidle2ordomcontentloaded, then wait for a specific selector. Polling and WebSockets can prevent zero in-flight requests.- The screenshot shows a loading skeleton: wait for the component’s ready selector or a predicate on its status, not merely
load. - Images are missing: the page may lazy-load below the fold or fetch images after navigation. Add an application-specific readiness check and allow enough time for those requests.
- A selector wait expires: verify the selector in the same viewport and state, check whether the element is inside a frame, and confirm that the application really emits that marker on success.
- A click wait hangs: the click may update the page without navigation. Replace
waitForNavigation()withwaitForSelector()orwaitForFunction(). - The output file is incomplete or absent: ensure the screenshot call is awaited and that the browser remains open until it resolves.
- Captures differ between runs: live content or animation is changing. Capture a stable application state and use consistent viewport settings.
Performance and reliability decisions
Every extra wait increases latency, so make each one serve a distinct purpose. A useful sequence is: navigate with domcontentloaded when early work is sufficient, wait for the exact ready selector, and use waitForNetworkIdle() only when late requests themselves are relevant. Conversely, a mostly static marketing page may need only networkidle2.
Keep timeouts bounded and log which boundary failed. A navigation timeout indicates that the main resource or chosen network condition did not complete. A selector timeout indicates that the expected visual state was never observed. These are different operational failures and should be retried or investigated differently. No wait mode guarantees that every resource has finished or that a page is visually complete; the correct boundary depends on the target application.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo returns a screenshot or PDF from one GET request, so you do not have to operate Puppeteer, Chromium, navigation waits, or cleanup code. It can wait for a selector, a delay, or network idle; load lazy images for full-page captures; click an element; run custom JavaScript; and set a cache TTL. Before capture it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets, with each cleanup step configurable. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
Recommended Free Tools
The API also supports element captures by CSS selector, dark mode, device presets or custom viewports, retina scale, PDF paper and page-range settings, custom CSS, hidden selectors, blocked ads or resource types, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, signed links, asynchronous jobs with signed webhooks, and bulk capture of up to 100 URLs per call. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
cURL
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}`);
See the ScreenshotNeo documentation for request parameters and response headers. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account to get started.
Best Value
FAQ
Is networkidle2 always better than networkidle0?
No. networkidle2 tolerates a small amount of ongoing traffic and is practical for many pages. Use networkidle0 only when zero active connections is realistic for that site.
Can I replace a readiness wait with setTimeout?
You can add a delay, but a selector or application predicate is usually more precise because it ends when the required state exists rather than after an arbitrary number of milliseconds.
Why does a successful navigation still produce an incomplete image?
Navigation completion is not visual completion. Late API calls, lazy resources, client rendering, and animations can continue after goto(). Add a wait tied to the element or state the screenshot must show.
What happens when the page never reaches the chosen condition?
The operation rejects when its timeout expires. Treat that as a diagnosable failure, record which wait failed, and choose a condition compatible with the page instead of removing timeouts.
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.




