Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows 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 reinstallRun your setup code in the page context after navigation and before the capture call. In Playwright or Puppeteer, await the script’s Promise, wait for a selector or application-ready signal, then take the screenshot or generate the PDF. If code must run before the site’s own JavaScript, install an initialization hook before navigation.
Choose the right injection point
There are two different jobs that are often called “running JavaScript before a screenshot.” Use the one that matches your requirement:
- Change the current page: navigate first, then call an evaluation method. This is the normal choice for hiding elements, opening a menu, selecting a tab, adding test data, or waiting for an application function.
- Change the browser environment before site code runs: install an initialization script before navigation. This is needed when you must replace a global, intercept an API, set a hook, or otherwise affect scripts during document startup.
An initialization script runs after the document is created but before the page’s scripts run. A normal evaluation runs against the already loaded document. The distinction matters: installing a hook after navigation cannot retroactively affect code that has already executed.
Playwright: evaluate setup, then capture
Here is a complete Node.js example. It navigates, waits for a stable network state, runs asynchronous page setup, waits for a meaningful selector, and captures the full page.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1
});
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForLoadState('networkidle');
await page.evaluate(async () => {
// Remove a banner and open the state required for the capture.
document.querySelector('.cookie-banner')?.remove();
document.querySelector('[data-tab="details"]')?.click();
// If the application exposes an async preparation function, await it.
if (typeof window.preparePage === 'function') {
await window.preparePage();
}
});
await page.waitForSelector('[data-capture-ready="true"]', { state: 'visible' });
await page.screenshot({ path: 'capture.png', fullPage: true });
await browser.close();
page.evaluate() executes in the browser page context. When the function returns a Promise, Playwright waits for it, so asynchronous DOM work, fetches, and application functions can finish before the screenshot call. Keep browser-side values inside the callback or pass serializable arguments explicitly; server-side variables are not automatically available in that context.
Install a pre-document hook
Use page.addInitScript() before goto() when the site must see your changes during startup. The hook is applied on navigations and child frames.
await page.addInitScript(() => {
// This runs after document creation and before page scripts.
Object.defineProperty(navigator, 'language', {
get: () => 'en-US'
});
window.__captureMode = true;
});
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForLoadState('networkidle');
await page.screenshot({ path: 'startup-hook.png', fullPage: true });
Do not use an initialization hook merely because it is available. For ordinary visual changes, evaluating after navigation is easier to reason about and lets you inspect the page before modifying it.
Rank #2
Puppeteer: the equivalent lifecycle
Puppeteer uses evaluateOnNewDocument() for pre-document code and page.evaluate() for code against the current page.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.evaluateOnNewDocument(() => {
window.__captureMode = true;
});
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForNetworkIdle({ idleTime: 500, timeout: 30000 });
await page.evaluate(async () => {
document.querySelector('.cookie-banner')?.remove();
if (typeof window.preparePage === 'function') {
await window.preparePage();
}
});
await page.waitForSelector('[data-capture-ready="true"]', { visible: true });
await page.screenshot({ path: 'capture.png', fullPage: true });
await browser.close();
Puppeteer documents screenshot output as image bytes or base64 when requested. Saving directly to a path is usually simplest for a file workflow; returning bytes is useful when uploading to object storage or an API.
Make asynchronous pages deterministic
Wait for an application signal
networkidle is a useful broad checkpoint, not proof that the page is visually ready. A single-page app may fetch data later, keep a websocket open, or render after a framework transition. Prefer a selector or explicit flag that represents the state you need:
await page.evaluate(async () => {
await window.prepareInvoice?.();
document.documentElement.dataset.captureReady = 'true';
});
await page.waitForSelector('html[data-capture-ready="true"]');
Scroll to trigger lazy content
Full-page capture does not guarantee that every lazy image has loaded. Scroll through the document, allow rendering time, and then capture.
await page.evaluate(async () => {
for (let y = 0; y < document.body.scrollHeight; y += 800) {
window.scrollTo(0, y);
await new Promise(resolve => setTimeout(resolve, 100));
}
window.scrollTo(0, 0);
});
await page.screenshot({ path: 'lazy-loaded.png', fullPage: true });
For a PDF, use the same preparation lifecycle but call the PDF method with explicit paper size, margins, orientation, and page-range options. A PDF is paginated output; it will not necessarily match an image’s continuous full-page layout.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Useful setup patterns
Hide an element without changing application code
await page.addStyleTag({ content: '.chat-widget, .newsletter-modal { display: none !important; }' });
Click, fill, and capture a state
await page.getByRole('button', { name: 'Show details' }).click();
await page.locator('#email').fill('[email protected]');
await page.waitForSelector('.details-panel[data-loaded="true"]');
Return diagnostics from the page
const state = await page.evaluate(() => ({
title: document.title,
height: document.documentElement.scrollHeight,
ready: document.readyState,
images: [...document.images].filter(image => !image.complete).length
}));
console.log(state);
Collecting this state before capture makes failures easier to distinguish: an absent selector, an incomplete image, or a page that never reached its application-ready condition.
Rank #4
Common failures and fixes
- Your script has no visible effect: it may run in the wrong context, target a selector that has not been rendered, or be overwritten by a later framework update. Evaluate after the relevant component appears, or use an initialization hook only for startup behavior.
- The screenshot contains a loading spinner: replace a generic timeout with a selector, data attribute, or page function that proves content is ready. Await that condition immediately before capture.
- Lazy images are blank: scroll the page to trigger intersection observers, wait for image completion, and verify the count of incomplete images before taking the shot.
- The evaluation times out: an awaited Promise may never resolve because a request failed or an application callback is unavailable. Add an application-level timeout, log errors inside the page, and capture diagnostic state.
- A pre-document hook is too late: register
addInitScript()orevaluateOnNewDocument()beforegoto(). Installing it after navigation affects only later navigations. - Frames are unchanged: identify the frame containing the target element and evaluate in that frame. Initialization scripts are applied to child frames, but ordinary page evaluation targets the main frame unless you select another.
- Headless and headed output differ: set the viewport, device scale, color scheme, fonts, timezone, and other environment inputs explicitly. Also allow web fonts and transitions to settle.
- Consent or bot screens block the page: treat the response as a capture failure, not as a successful screenshot. Authenticate or provide the required browser state only where you are authorized to do so.
Operational choices: in-process browser or managed API
Playwright and Puppeteer give you application-owned control over browser lifecycle, JavaScript, frames, authentication, and custom diagnostics. You must provision browsers, manage concurrency, isolate jobs, enforce timeouts, and store outputs.
A managed endpoint reduces browser operations. Browserless provides a /screenshot endpoint with addScriptTag entries for a URL or inline script content, a /function endpoint for custom server-side Puppeteer code, and a /pdf endpoint for rendered PDFs. Its documented controls include waiting for events, functions, selectors, and timeouts; scrolling can be enabled for lazy content. The trade-off is less local control and the need to authenticate and handle a remote service’s response.
Whichever route you choose, make readiness part of the capture contract: install startup hooks before navigation, await setup Promises, wait for a meaningful condition, trigger lazy content, then capture. Keep screenshots and PDFs as separate output paths because pagination and rendering requirements differ.
Best Value
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
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}`);
Its 63 options include custom JavaScript and CSS, selector waits, delays and network-idle waits, clicks, hidden selectors, full-page lazy-image loading, element capture, device presets, arbitrary viewports, dark mode, retina scale, headers, cookies, user agents, Authorization, timezone, geolocation, request blocking, transparent backgrounds, resizing, cache TTLs, signed links, asynchronous webhooks, bulk capture of 100 URLs per call, usage reporting, and PDF controls. An MCP server exposes take_screenshot, get_page_info, and capture_pdf for 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; every feature is on every plan, and yearly billing gives two months free. See the ScreenshotNeo documentation for parameters and setup, then sign up free to get 1,000 screenshots a month without a card.
Frequently Asked Questions
Should I use an initialization script for every screenshot?
No. Use normal page evaluation for changes to an already loaded document. Reserve initialization scripts for behavior that must exist before the site’s scripts execute.
Can JavaScript change a PDF as well as an image?
Yes. Run the same preparation lifecycle before calling the PDF API, but set paper, margins, orientation, and page ranges explicitly because PDF pagination differs from a continuous image.
What is a reliable replacement for a fixed sleep?
Wait for an application-specific selector, data attribute, event, or function result that represents the exact state you intend to capture.
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.

