For a normal navigation, await page.goto(url) and inspect the returned HTTPResponse. To run JavaScript before the page’s own scripts, call page.evaluateOnNewDocument() before navigating. These solve different problems: goto() reads what the browser received, while evaluateOnNewDocument() installs code in each new document before its scripts execute.
The four Puppeteer operations, in one view
Confusion usually comes from treating navigation, request interception, and page evaluation as interchangeable. Choose the API by what you need to control.
| Goal | API | When it runs | What it controls |
|---|---|---|---|
| Read a navigation response | page.goto() |
During a navigation | The response returned by the browser for the navigation |
| Supply a replacement response | HTTPRequest.respond() |
While request interception is active | The content, status, headers, and body delivered for an intercepted request |
| Run code in the current document | page.evaluate() |
After the document already exists | JavaScript executed in the page context now |
| Install code before page scripts | page.evaluateOnNewDocument() |
After a document is created, before its scripts run | Code that is injected into future documents, including attached or navigating child frames |
A successful navigation is not necessarily a successful HTTP transaction. A 404 or 503 can still produce a completed HTTPResponse, so always inspect its status.
Read the document response from page.goto()
page.goto() returns the response associated with the navigation. It can return null for about:blank and for a same-URL hash navigation, so use optional chaining or an explicit null check.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
const response = await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 30_000
});
if (!response) {
console.log('No document response (about:blank or hash-only navigation).');
} else {
console.log('URL:', response.url());
console.log('Status:', response.status());
console.log('OK:', response.ok());
console.log('Content type:', response.headers()['content-type'] || 'not supplied');
}
} finally {
await browser.close();
}
The response object is for reading the navigation result; it is not a request-interception hook. Check the status before treating the page as available to your application. Depending on your workflow, you may also wait for networkidle0 or a specific selector after the response arrives, but those waits describe page readiness, not HTTP success.
Run JavaScript before any site script
Register the function before calling goto(). Puppeteer runs the function after the new document is created but before that document’s scripts run. The registration also applies when child frames attach or navigate.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.evaluateOnNewDocument(() => {
// This executes in every future document before its scripts.
window.__automationFlag = true;
Object.defineProperty(navigator, 'language', {
get: () => 'en-US'
});
});
try {
const response = await page.goto('https://example.com', {
waitUntil: 'domcontentloaded'
});
const values = await page.evaluate(() => ({
flag: window.__automationFlag,
language: navigator.language
}));
console.log('HTTP status:', response?.status());
console.log(values);
} finally {
await browser.close();
}
The function passed to evaluateOnNewDocument() is serialized and executed in the browser context. Keep it self-contained: imported Node.js variables, modules, and closures are not automatically available there. Pass simple values as arguments when needed.
Use page.evaluate() for the current page
page.evaluate() is the right tool after navigation when you need to inspect or modify the document that is already loaded. Puppeteer waits when the evaluated function returns a Promise.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
const title = await page.evaluate(() => document.title);
const result = await page.evaluate(async () => {
const response = await fetch('/api/status');
return {
status: response.status,
text: await response.text()
};
});
console.log(title, result);
It cannot retroactively run before scripts that have already executed. If a site reads a global during startup, install that global with evaluateOnNewDocument() before navigation instead.
Supply a response with request interception
HTTPRequest.respond() is for fulfilling an intercepted request with your own response. Enable interception first, then resolve every intercepted request with continue(), respond(), or abort().
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
if (request.url().endsWith('/feature-flags.json')) {
void request.respond({
status: 200,
contentType: 'application/json',
headers: { 'Cache-Control': 'no-store' },
body: JSON.stringify({ newHeader: true })
});
} else {
void request.continue();
}
});
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
} finally {
await browser.close();
}
Once interception is enabled, requests stall until something resolves them. A handler that forgets to continue, respond, or abort can make navigation appear hung.
Prevent duplicate interception resolutions
Multiple listeners or asynchronous handlers can race. Before resolving a request, check request.isInterceptResolutionHandled(). If you awaited an asynchronous operation, check again immediately before calling continue(), abort(), or respond(), because another handler may have completed it during the wait.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
page.on('request', async request => {
if (request.isInterceptResolutionHandled()) return;
const shouldMock = request.url().includes('/config');
if (!shouldMock) {
await request.continue();
return;
}
// Re-check after any asynchronous work.
await Promise.resolve();
if (request.isInterceptResolutionHandled()) return;
await request.respond({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ enabled: true })
});
});
Choose the timing deliberately
- Need the server’s navigation result? Use
const response = await page.goto(url)and inspectstatus(), headers, and URL. - Need to mock or replace network content? Enable interception and call
request.respond()for matching requests; resolve all others. - Need to inspect the loaded DOM? Use
page.evaluate()after navigation. - Need a variable or shim present during startup? Register
evaluateOnNewDocument()before navigation.
These APIs can be combined. For example, install a startup flag, navigate, inspect the returned status, then evaluate DOM data. Interception is independent of early-script injection: it changes network delivery, while evaluateOnNewDocument() changes the JavaScript environment in newly created documents.
Common failures and fixes
response is null
This is expected for about:blank and same-URL hash navigation. Guard the value and, if you require a network response, navigate to a document URL rather than only changing the fragment.
The page loaded but the test reports success
Navigation completion does not guarantee a 2xx status. Log response?.status() and fail or branch on 404, 503, and other error statuses explicitly.
The early script has no effect
Register it before page.goto(). Calling page.evaluate() afterward is too late for code that the site reads during startup. Also ensure the injected function does not depend on Node-only variables.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Navigation hangs after interception is enabled
At least one request was left unresolved. Add a default request.continue() path and resolve every branch. If several listeners exist, use isInterceptResolutionHandled() to avoid competing resolutions.
respond() throws or is ignored
Confirm that request interception was enabled and that the request has not already been resolved by another listener. A response supplied to respond() should include the fields your page needs, such as status, content type, headers, and body.
The early code works in the main page but not a frame
evaluateOnNewDocument() is intended to apply when child frames attach or navigate. Verify that the frame is created after registration and that your test is evaluating the expected frame rather than the top-level page.
Reliability and performance considerations
- Set an explicit navigation timeout and choose a
waitUntilcondition that matches the test. Waiting for network idle can take longer on pages with persistent connections than waiting fordomcontentloaded. - Keep interception predicates cheap and narrow. Inspecting every request and performing asynchronous work in the handler increases page startup time.
- Use one clearly owned interception handler where possible. Multiple listeners require resolution checks and make failures harder to diagnose.
- Capture status, final URL, and relevant response headers in logs. This distinguishes server errors from browser timing problems.
- Close the browser in a
finallyblock so failed navigations do not leak Chromium processes.
Or skip the browser setup
If your goal is a clean website image or PDF rather than Puppeteer control, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners as a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks, 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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
curl -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 the options and response details. The same endpoint supports PNG, JPEG, WebP, or PDF output; full-page shots with lazy images, CSS-selector element capture, device presets, custom viewport and retina scale, dark mode, custom CSS and JavaScript, clicks, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification. Its parameter names also accept the names used by other screenshot APIs, which can simplify migration.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
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 also includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Sign up for the free plan.
FAQ
Does page.goto() throw on every HTTP error?
No. HTTP error responses can still complete as responses, so inspect the returned status instead of assuming navigation completion means success.
Can early-document code modify the server response?
No. It runs in the page’s JavaScript context. Use request interception and respond() when you need to supply network content.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsWhat happens to requests that do not match my mock?
They still require a resolution. Call request.continue() for the normal network path.
Frequently Asked Questions
Does page.goto() throw on every HTTP error?
No. HTTP error responses can still complete as responses, so inspect the returned status instead of assuming navigation completion means success.
Can early-document code modify the server response?
No. It runs in the page’s JavaScript context. Use request interception and respond() when you need to supply network content.
What happens to requests that do not match my mock?
They still require a resolution. Call request.continue() for the normal network path.
Recommended Free Tools
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.

