Free tools Windows power users keep installed
One-click scans. No signup required.
Use a Playwright Page and await page.goto('https://example.com'). The call performs a direct navigation, waits for the load event by default, and returns the main-resource response when one exists. Create the browser, context, and page first; then close the context and browser after the work is complete.
Minimal direct navigation
This complete Node.js example launches Chromium, opens an isolated browser context, navigates to an absolute URL, checks the HTTP response, and closes resources in the correct order:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
const response = await page.goto('https://example.com');
if (response) {
console.log('status:', response.status());
console.log('final URL:', page.url());
} else {
console.log('No main-resource response was returned.');
}
await context.close();
await browser.close();
})();
The URL should normally include a scheme such as https://. If the context has a baseURL, a relative path can be resolved against it. Playwright documents goto and its return behavior in the Page API reference.
What page.goto() waits for
Navigation has several useful milestones. Select the one that matches what your code needs rather than assuming that one state is correct for every site.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
load: the default
With no options, page.goto() waits for the page’s load event. This is a practical default when scripts, stylesheets, images, and other load-event resources must be available before the next step.
commit: response accepted
commit resolves as soon as the response is received and document loading starts. It is useful when you need to begin work early, such as inspecting the destination or waiting for a separate application signal.
domcontentloaded: HTML parsed
This state resolves after the initial HTML has been parsed, without waiting for every load-event resource. It can shorten workflows that only need the document structure.
networkidle: rarely the right test signal
networkidle waits for a period with no active network connections. Modern applications may poll, stream, or load data lazily, so this state can be delayed or never represent a meaningful user-ready screen. Playwright explicitly says not to use this method as a general testing strategy; use web assertions to assess readiness instead. See the Page API and navigation guide.
await page.goto('https://example.com/dashboard', {
waitUntil: 'domcontentloaded'
});
For a test, assert the outcome a user needs. For example:
const { test, expect } = require('@playwright/test');
test('dashboard opens', async ({ page }) => {
await page.goto('https://playwright.dev/');
await expect(page.getByRole('heading', { name: 'Get started' })).toBeVisible();
});
The heading, role, or other assertion must match your application; the important pattern is to verify visible behavior instead of treating a lifecycle event as proof that the page is ready.
Rank #2
Absolute URLs, base URLs, and the current address
Use an absolute URL by default
Pass a complete URL, including https:// or http://:
await page.goto('https://www.example.com/products');
An invalid URL can cause navigation to fail. A string without a scheme is not automatically treated as a web address unless it can be resolved through a configured base URL.
Resolve paths with baseURL
Set baseURL when all routes belong to the same application:
const context = await browser.newContext({
baseURL: 'https://example.com'
});
const page = await context.newPage();
await page.goto('/products');
This keeps test routes short while retaining a single host configuration.
Read the resulting URL
Call page.url() after navigation to obtain the address currently shown in the page:
await page.goto('https://example.com/start');
console.log(page.url());
Redirects may mean that the final URL differs from the one supplied to goto.
Rank #3
Navigation caused by a click or form submission
Use goto for direct navigation. A click, link activation, or form submission can trigger navigation implicitly, so coordinate the URL wait with the action. Start waiting before the action to avoid missing a fast navigation:
const urlWait = page.waitForURL('**/account');
await page.getByRole('link', { name: 'Account' }).click();
await urlWait;
console.log('arrived at:', page.url());
waitForURL accepts a glob, regular expression, URL pattern, or predicate. An un-wildcarded string is an exact URL match. You can also verify the resulting page content:
await page.waitForURL(//account(?:?|$)/);
await expect(page.getByRole('heading', { name: 'Account' })).toBeVisible();
This distinction between explicit and interaction-triggered navigation is described in the Pages guide and the Page API.
Inspecting responses, redirects, and HTTP errors
Check the returned response
page.goto() returns the response for the main resource in normal cases. Inspect its status when an HTTP success response is required:
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 →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →const response = await page.goto('https://example.com/report');
if (!response) {
throw new Error('Navigation returned no main-resource response');
}
if (!response.ok()) {
throw new Error(`HTTP status: ${response.status()}`);
}
A 404 or 500 response does not, by itself, make goto throw. The navigation can complete while the response reports an error status, so check status() or ok() explicitly. Playwright documents this behavior in the Page API.
Understand redirects
For server redirects, the navigation resolves with the first non-redirect response. A client-side redirect that occurs before load makes Playwright wait for the redirected page’s load event. Always use page.url() or an assertion when the destination matters.
Know when null is expected
The return value can be null for about:blank and for navigation to the same URL’s fragment. Do not treat a null response alone as a failed navigation; decide whether your workflow expected a network response.
Timeouts and failure handling
Navigation can fail for an invalid URL, SSL error, timeout, unreachable server, or failure to load the main resource. Give the operation a timeout appropriate to your environment and capture a useful error:
Recommended Free Tools
try {
await page.goto('https://example.com/slow', {
waitUntil: 'domcontentloaded',
timeout: 30_000
});
} catch (error) {
console.error('Navigation failed:', error.message);
console.error('URL at failure:', page.url());
throw error;
}
For a suite-wide policy, configure the navigation timeout on the page or context; use a per-call value when one route is known to need different treatment. Avoid solving every timeout by choosing networkidle: an assertion on the required heading, table, or state is usually more deterministic.
Contexts, pages, and state isolation
A Page is a tab or popup inside a BrowserContext. A context can contain multiple pages, while separate contexts isolate cookies and cache. This lets you test different users or sessions without state leaking between them:
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'en-US'
});
const firstPage = await context.newPage();
const secondPage = await context.newPage();
await firstPage.goto('https://example.com/one');
await secondPage.goto('https://example.com/two');
Context-level settings apply to its pages, including viewport, locale, and network routing. Create another context when you need independent cookies or cache. Close a directly created context before the browser so HAR files, videos, and other context artifacts can be flushed. The Browser API covers lifecycle details, and the Pages guide explains the page/context model.
Common problems and precise fixes
“Protocol error” or invalid URL
Cause: The string is malformed or lacks a resolvable scheme/base URL.
Fix: Pass an absolute URL such as https://example.com, or configure baseURL and use a valid path.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
The call completes but the app is still rendering
Cause: The application populates data after the load event.
Fix: Wait for the specific heading, locator, URL, or application state your workflow requires. Use expect(...).toBeVisible() or a suitable locator assertion instead of a fixed sleep.
A 404 does not throw
Cause: HTTP error statuses are responses, not necessarily transport failures.
Fix: Store the response and check response.ok() or response.status().
A click-navigation wait intermittently times out
Cause: The URL wait was started after the click, or the action did not navigate at all.
Fix: Create the waitForURL promise before clicking, then verify that the control actually changes the URL or opens a popup.
Authentication or locale differs between runs
Cause: Cookies, cache, viewport, locale, or routes belong to a different context configuration.
Fix: Set those options when creating the context and use separate contexts for separate identities.
The browser closes before artifacts are complete
Cause: The browser was closed while its context still had files to flush.
Fix: Close the context first, then the browser.
Performance and reliability choices
- Reuse one browser process when practical, but create a fresh context for each isolated user or test scenario.
- Choose
commitordomcontentloadedwhen the next operation does not need every load resource. - Use assertions tied to user-visible state for single-page applications and lazy-loaded content.
- Check the main response status when availability or correctness depends on HTTP success.
- Keep URL waits and action-triggered navigation paired so fast transitions are not missed.
- Set viewport, locale, cookies, and routes at context creation so navigation is reproducible.
Or skip the browser setup
If your goal is a clean image or PDF rather than browser automation, ScreenshotNeo accepts one request with a URL. It handles consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.
Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every feature is included on every plan. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);
See the ScreenshotNeo documentation for request options. Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
Frequently Asked Questions
Can two pages in one Playwright context navigate at the same time?
Yes. A context can contain multiple pages, and each page can call goto() independently. They still share that context’s cookies, cache, and emulation settings.
What should I log when a navigation failure is intermittent?
Log the requested URL, page.url() at failure, the navigation timeout, and any returned response status. This separates an HTTP error response from a transport or timeout failure.
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.

