Use a real browser automation tool, then wait for a condition that proves the content you need is visible before capturing the page. A navigation event such as load does not necessarily mean an app’s later JavaScript work, lazy-loaded content, or animations have finished. When you control the site, wait for an app-specific ready marker; otherwise wait for the target element or text.
Choose a readiness signal, not just a delay
Browser navigation milestones describe document loading, not every app-specific task. A page may render important content after the initial load, while a fixed sleep can end too early on a slow run and waste time on a fast one. Prefer an observable condition tied to the final UI you want in the screenshot.
- Best when you control the site: expose a stable ready marker, such as
data-page-ready="true", after the relevant content is rendered. - When you do not control it: wait for the target element to become visible, or for specific text or another page condition to appear.
- Use network idle cautiously: it describes network activity, not visual readiness. Playwright defines it as no network connections for at least 500 ms and discourages it as a testing readiness strategy.
The examples below use https://example.com and a sample ready marker. Replace both with the target URL and a selector or condition that actually indicates the content you need.
Capture with Playwright
Playwright provides navigation milestones, locator waits, predicate waits, and screenshot options. The separate navigation and locator waits below are intentional: the first starts the document, and the second waits for the app-specific state.
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 glitches#1 Best Overall
Install
In a new Node.js project, install Playwright with npm install playwright. If the browser binaries are not already installed, run npx playwright install chromium.
Runnable JavaScript example
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
// Replace with a real marker or target element on the site.
await page.locator('[data-page-ready="true"]').waitFor({
state: 'visible',
timeout: 15000,
});
await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
await browser.close();
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
For an existing target element, replace the sample selector with a selector for that element. If there is no suitable element, use page.waitForFunction() with a specific predicate—for example, a condition based on a known application state. Set a finite timeout so a missing condition fails clearly rather than hanging indefinitely.
Choose the screenshot scope
page.screenshot({ path: 'page.png' })captures the current viewport.page.screenshot({ path: 'page.png', fullPage: true })captures the full scrollable page.page.screenshot()without a path returns a buffer you can post-process or pass to a pixel-diff workflow.
Capture with Puppeteer
Puppeteer’s screenshot guide demonstrates navigating with networkidle2 and then taking a screenshot. Treat that as a convenient pattern, not a guarantee that a dynamic app has reached the exact visual state you want. If the important content appears later, add a wait for its element or state.
Rank #2
- Intuitive interface of a conventional FTP client
- Easy and Reliable FTP Site Maintenance.
- FTP Automation and Synchronization
Install
Install Puppeteer in a Node.js project with npm install puppeteer.
Recommended Free Tools
Runnable JavaScript example
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 30000,
});
// Replace with a real selector for the content you need.
await page.waitForSelector('[data-page-ready="true"]', {
visible: true,
timeout: 15000,
});
await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
await browser.close();
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
For a single widget or region, select its element and call element.screenshot() instead of taking a page screenshot. Puppeteer documents that an element screenshot scrolls the element into view if it is hidden.
Capture with Selenium WebDriver
driver.get(url) waits for document loading, but content that is populated afterward may need an explicit condition wait. The following JavaScript example uses Selenium’s WebDriver bindings and waits until a marker is displayed.
Rank #3
Install
Install the JavaScript package with npm install selenium-webdriver and ensure a compatible browser driver is available in your environment.
Runnable JavaScript example
const { Builder, By, until } = require('selenium-webdriver');
(async () => {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com');
const ready = await driver.wait(
until.elementLocated(By.css('[data-page-ready="true"]')),
10000,
'Page-ready marker did not appear'
);
await driver.wait(until.elementIsVisible(ready), 10000);
const pngBase64 = await driver.takeScreenshot();
require('fs').writeFileSync('page.png', Buffer.from(pngBase64, 'base64'));
} finally {
await driver.quit();
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
The sample captures a PNG of the current browser view. Selenium’s screenshot API returns base64 data; the example decodes it and writes the image to disk.
Which capture method fits?
| What you need | Use | Notes |
|---|---|---|
| What is currently visible in the browser | Viewport screenshot | Useful for a fixed viewport or a specific visual state. |
| The whole scrollable page | Full-page screenshot | Supported by Playwright and Puppeteer screenshot APIs; check the method’s options in your installed version. |
| One chart, widget, or content region | Element screenshot | Puppeteer documents element screenshots and scrolls the target into view if hidden. |
| Image data for further processing | Screenshot buffer | Playwright can return a buffer for post-processing or pixel-diff use. |
Common problems and fixes
The screenshot misses the JavaScript-rendered content
The wait condition may only indicate that navigation occurred, not that the target content appeared. Wait for the target element to become visible, a ready marker to change state, or a specific piece of text to appear. If you control the app, set the marker only after the content relevant to the screenshot is rendered.
Rank #4
Network idle never arrives, or arrives before the page looks ready
Network activity is a heuristic, not a promise of visual completeness. Long-running requests can keep it from settling; conversely, the page can be visually incomplete after traffic pauses. Replace it or supplement it with a condition tied to the required UI.
The page is cut off
Use a full-page option when the desired output is the entire scrollable document. If you only need one region, capture that element instead of the whole page.
The target is below the fold
Some capture methods scroll an element into view for an element screenshot. If the page renders content only after scrolling, perform the same scroll or interaction the site requires, then wait for the resulting content before capturing.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
A wait times out
Confirm the selector exists on the loaded page, is not inside an inaccessible frame, and can become visible in the current state. Increase the timeout only when the content legitimately needs longer; do not hide a wrong selector by using a very long timeout.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo can return a screenshot or PDF from one GET request. Its clean-shot steps can accept consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. It supports waits for a selector, a delay, or network idle, so choose a condition appropriate to the page. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; responses identify the page verdict and billing status in headers. Its MCP server provides screenshot tools for AI agents, including Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to try it with 1,000 screenshots a month and no card.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
FAQ
Does “JavaScript finished loading” have one universal browser event?
No. A browser lifecycle event does not define when every application-specific task or visual update is complete. The relevant condition depends on the page and the content you need.
Can I use a fixed sleep?
You can, but it is not a reliable readiness test: it may be too short on one run and longer than necessary on another. Prefer a page condition that can be checked directly.
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.




