For a normal HTML login form, get the username and password in your Node.js process, open the authorized login page, locate the controls with Puppeteer locators, fill them, submit, and wait for the site’s real authenticated signal. Use page.authenticate() only for an HTTP authentication challenge; it does not type into ordinary username and password fields.
The example below uses environment variables so secrets are not placed in source code. Replace its URL, selectors, and success condition with those from the application you are authorized to automate.
Complete Puppeteer example
This ES-module script handles a conventional form that navigates to another document after submission:
import puppeteer from 'puppeteer';
const username = process.env.LOGIN_USERNAME;
const password = process.env.LOGIN_PASSWORD;
if (!username || !password) {
throw new Error('Set LOGIN_USERNAME and LOGIN_PASSWORD before running');
}
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.test/login', { waitUntil: 'domcontentloaded' });
await page.locator('input[name="username"]').fill(username);
await page.locator('input[name="password"]').fill(password);
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.locator('button[type="submit"]').click(),
]);
await page.locator('[data-testid="account-menu"]').wait();
console.log('Login succeeded');
} finally {
await browser.close();
}
Puppeteer’s page-interactions guide recommends locators because they wait for an element to be present and ready for the requested action. See the page interactions guide. The URL, selectors, and data-testid in this listing are placeholders, not universal values.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Before you automate
Install and choose a module format
In a new project, install Puppeteer with npm install puppeteer. The package downloads a compatible browser unless your project is configured to use an existing executable. The script above uses modern ES modules; set "type": "module" in package.json, or convert the imports and top-level awaits to your project’s module style.
Supply credentials at runtime
Set LOGIN_USERNAME and LOGIN_PASSWORD through your deployment platform’s secret injection or your local shell. For example, on a Unix-like shell:
LOGIN_USERNAME='alice@example.com' LOGIN_PASSWORD='use-a-secret-store' node login.js
The Puppeteer API documentation does not prescribe a particular secret-management product. Keep the values out of source control, command history where practical, logs, screenshots, crash dumps, and error messages. Never print the password to diagnose a failed run.
Find and fill the right controls
Prefer stable selectors
Use a field’s name, associated label, accessible role, or a test ID supplied by the application. Puppeteer selectors support CSS and Puppeteer-specific syntax for text, accessibility attributes, XPath, and shadow DOM; the available selector should reflect the page’s actual markup. A selector such as input:nth-of-type(2) is fragile because an unrelated field can change the position.
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 →Repair Windows errors before they cause bigger problemsFix Now →await page.locator('input[name="email"]').fill(username);
await page.locator('input[autocomplete="current-password"]').fill(password);
If the site exposes labels, an accessibility-oriented locator can be clearer:
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
await page.getByLabel('Email address').fill(username);
await page.getByLabel('Password').fill(password);
Confirm the selector identifies the intended control. A locator can wait for readiness, but it cannot tell whether you selected the username field, whether the credentials are valid, or whether the application accepted them.
When the form is in an iframe
A document inside an iframe has its own browsing context. Locate the frame, then use that frame’s page-like API (or a frame locator in the Puppeteer version you use) to find and fill the controls. Inspect the frame URL and name rather than assuming the first iframe is the login form. Cross-origin policy still applies: automation does not grant permission to read an unrelated origin’s content.
fill() versus keyboard typing
Use fill() for ordinary fields
Locator.fill() accepts a string for inputs, textareas, selects, and contenteditable controls. It is the concise choice for normal form assignment and includes locator waiting behavior. Its reference is at pptr.dev’s Locator.fill() documentation.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use typing APIs when key events matter
page.type() and page.keyboard.type() generate keyboard and input events character by character. Use them only when the application genuinely depends on those events—for example, a widget that validates each keystroke or masks input in a way that does not respond correctly to a direct fill.
await page.locator('input[name="username"]').click();
await page.keyboard.type(username, { delay: 20 });
await page.locator('input[name="password"]').click();
await page.keyboard.type(password, { delay: 20 });
The method references are Page.type() and Keyboard.type(). Do not add an arbitrary delay as a substitute for waiting on a real condition.
Rank #3
Submit and determine whether login succeeded
Full document navigation
A click and navigation can race if started separately. Start both promises together:
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.locator('button[type="submit"]').click(),
]);
Puppeteer’s waitForNavigation() can resolve with a response, or with null for History API and anchor navigation. A resolved wait therefore does not prove that authentication worked; check a page-specific authenticated signal afterward.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteSingle-page applications
Many React, Vue, and other SPA logins update the current document instead of navigating. Do not wait forever for a URL load. Click, then wait for a reliable authenticated element, URL change, response, or application state:
await page.locator('button[type="submit"]').click();
await page.locator('[data-testid="account-menu"]').wait();
If the application changes the URL without a document load, wait for the expected URL or use a success element. A fixed sleep is weaker because network and server timing vary.
Detect rejected credentials
Wait for either the success signal or a visible error, with a bounded timeout, so a bad password does not look like a hung test:
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
const success = page.locator('[data-testid="account-menu"]');
const error = page.locator('[role="alert"]');
await page.locator('button[type="submit"]').click();
try {
await Promise.race([
success.wait(),
error.wait(),
]);
} catch {
throw new Error('Neither a success indicator nor a login error appeared');
}
if (await error.isVisible().catch(() => false)) {
throw new Error('The application rejected the supplied credentials');
}
Adapt this logic to the application’s actual error markup. Do not include the username or password in the thrown message.
HTTP authentication is a different flow
When the server responds with an HTTP authentication challenge, there may be no HTML form to fill. Use page.authenticate() before requesting the protected page:
await page.authenticate({
username: process.env.HTTP_AUTH_USERNAME,
password: process.env.HTTP_AUTH_PASSWORD,
});
await page.goto('https://example.test/protected', { waitUntil: 'domcontentloaded' });
The Page.authenticate() reference describes credentials for HTTP authentication and notes that request interception is enabled behind the scenes, which can have a performance cost. It is not a replacement for locating and filling an HTML login form.
Common failures and fixes
“Waiting failed” or a selector timeout
- Cause: The selector does not match the rendered markup, the form has not appeared, or the control is inside an iframe or shadow root.
- Fix: Inspect the live DOM, use a stable name, label, role, or test ID, wait for the relevant container, and switch to the correct frame or shadow-DOM selector.
The click does nothing
- Cause: A disabled button, client-side validation error, overlay, or an event-dependent widget prevented submission.
- Fix: Wait for the button to be actionable, inspect visible validation messages, dismiss only expected overlays, and try keyboard typing if the site requires key events.
waitForNavigation() never resolves
- Cause: The login is an SPA transition or uses History API rather than a document navigation.
- Fix: Remove the navigation wait and wait for the authenticated UI, URL, response, or state that the application actually produces.
The script reports success but the session is not authenticated
- Cause: The chosen success selector exists on both anonymous and authenticated pages, or it appeared before the request completed.
- Fix: Choose a signal unique to the signed-in state, then verify a protected page or account-specific request when permitted.
Credentials are rejected despite looking correct
- Cause: Wrong tenant or login URL, a required hidden field, an account lock, an unhandled consent step, or a site-specific second factor.
- Fix: Confirm the authorized login endpoint and required fields, inspect the application’s visible error, and implement the site’s permitted authentication flow. Do not attempt to bypass multi-factor authentication, bot checks, or access controls.
Unexpected blank pages or browser crashes
- Cause: Browser launch configuration, resource limits, or a page that takes longer to load.
- Fix: Capture only non-sensitive diagnostics, set purposeful navigation and locator timeouts, close the browser in a
finallyblock, and tune concurrency to the available CPU and memory.
Reliability, performance, and privacy practices
- Set a navigation timeout appropriate to the application and keep locator waits bounded; unlimited waits turn an outage into a stuck worker.
- Reuse a browser process for a controlled batch, but create an isolated context or profile per account so cookies and local storage cannot leak between users.
- Close pages, contexts, and the browser even on failure. The
try/finallypattern in the example prevents orphaned Chromium processes. - Do not enable request or page logging that records form bodies, authorization headers, cookies, or screenshots containing credentials.
- Capture diagnostics only after redacting secrets. A screenshot of a password field, autofill suggestion, or account identifier can itself be sensitive.
- Respect the site’s terms and rate limits and automate only accounts and pages for which you have authorization.
Version and API notes
Puppeteer reference pages found for this guidance carry different version labels: locator documentation was shown as 25.12.0, Page.type() as 25.10.0, and Keyboard.type() as 25.9.0. Treat the behavior described here as documentation current on September 29, 2026, and check the API reference and installed package before pinning code to a specific version. The getting started guide covers project setup, while the Locator class reference lists locator behavior.
Or skip the browser setup
If your goal is a clean image or PDF of a page rather than an interactive login workflow, ScreenshotNeo provides a one-request website screenshot API. It accepts the consent banner as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. 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.
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 reinstallSee the ScreenshotNeo API documentation for all options. A cURL request is:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.test/login -o shot.webp
ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It supports full-page captures with lazy images loaded, CSS-selector element captures, device presets and custom viewports, dark mode, retina scale, PDF paper and page settings, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work.
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Create a free ScreenshotNeo account to try it without a card.
Frequently Asked Questions
Can Puppeteer read credentials from a browser prompt?
For a normal form, obtain the values in your Node.js process and fill the page controls. Browser JavaScript dialogs and HTTP authentication challenges are separate mechanisms.
Recommended Free Tools
Should I use a fixed delay after clicking Login?
No. Wait for the application-specific success or error signal. Use navigation waiting only when the site actually performs a document navigation.
Can this automate a one-time passcode or MFA challenge?
Only implement an authentication flow that the account owner and site permit. This pattern does not bypass MFA, bot protection, or access controls.
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.

