Recommended Free Tools
In Puppeteer, each browser tab is a Page. To create a tab yourself, call browser.newPage() or context.newPage(). To handle a tab opened by a link, start waiting for the popup before clicking, then use the returned Page and call bringToFront() when you want to activate it. If the link navigates the current tab instead, wait for navigation on that same page alongside the click.
Choose the right approach for the link
First determine what the page should do. A link may open a separate tab or window, navigate the current tab, or leave the page unchanged because it was blocked or because the click did not reach the link. These outcomes need different waits: a popup wait for a new page, a navigation wait for the existing page, and diagnostic checks when neither happens.
| Goal or outcome | Starting point | Scope to consider |
|---|---|---|
| Create a page directly from your script | browser.newPage() or context.newPage() |
Choose whether it belongs in the browser’s default context or a particular context. |
| A site click opens a popup | Listen for the opener page’s popup event before clicking, or wait for a matching target in the context. |
Identify the intended new page; do not assume the first new target is necessarily the link you clicked. |
| A site click navigates the current tab | Run waitForNavigation() and the click together with Promise.all(). |
Wait on the page that is actually navigating. |
| Inspect pages already open | browser.pages() or context.pages() |
Browser-wide enumeration and context-scoped enumeration have different scope. |
Set up Puppeteer
The examples below use JavaScript with Node.js and Puppeteer. Install the package in your project:
npm install puppeteer
Save the example you want to run in a JavaScript file, such as tabs.js, then run it with node tabs.js. Puppeteer’s getting-started guide documents launching a browser, creating a page, and navigating to a URL. The documentation versions reviewed for the core APIs included Puppeteer 25.12.0; check the API reference for the version installed in your project if a method or event behaves differently.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Create a new tab directly
If the script—not a website link—should create the tab, create a new Page and navigate it. This is the simplest case because there is no popup timing to coordinate.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page.bringToFront();
console.log('Opened:', page.url());
} finally {
await browser.close();
}
})();
browser.newPage() creates a page in the browser’s default context. When your workflow already uses a particular browser context, use that context’s newPage() instead, so the page shares the intended context and its session state. A Page is Puppeteer’s handle for interacting with a browser tab; bringToFront() activates it. In headless automation, activation may not have a visible effect, but the method is useful when controlling a visible browser.
Click a link and capture its popup
When a website opens a new tab—for example, through a link with target="_blank"—subscribe to the opener page’s popup event before clicking. The popup is a separate Page in the same BrowserContext as the opener.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com');
const popupPromise = new Promise(resolve => {
page.once('popup', resolve);
});
await page.locator('a[target="_blank"]').click();
const popup = await popupPromise;
await popup.bringToFront();
console.log('Popup URL:', popup.url());
} finally {
await browser.close();
}
})();
Replace the selector with one that identifies the actual link on the site. Puppeteer recommends locators for element interaction: they wait for the element to be present and actionable before proceeding. If there may be more than one matching link, make the selector or locator target specific to the link you mean to click.
Why the wait comes before the click
The popup can be created as a direct result of the click. If the listener is installed afterward, a fast popup may already have fired its event. Creating popupPromise first ensures the script is waiting before it triggers the action. This is event-driven waiting guidance; the exact popup behavior still depends on the site and should be confirmed against the Puppeteer release you have installed.
Wait for a matching target instead
You can use BrowserContext.waitForTarget(predicate) when identifying the new page by a reliable condition is more suitable—for example, a URL pattern specific to the destination. Set up this wait before the click as well. Avoid taking whichever target appears first without checking it: a page can create unrelated targets, and concurrent activity can make the wrong one appear first.
Rank #3
const context = page.browserContext();
const targetPromise = context.waitForTarget(target =>
target.url().startsWith('https://example.com/destination')
);
await page.locator('a[target="_blank"]').click();
const target = await targetPromise;
const popup = await target.page();
if (!popup) {
throw new Error('The matching target did not expose a Page');
}
await popup.bringToFront();
console.log('Popup URL:', popup.url());
Choose a predicate that fits the site. A generic condition such as “the URL is not about:blank” may match an unrelated page. Some targets may not expose a normal page, so checking the result of target.page() avoids assuming that every matching target yields a Page.
Handle a link that navigates the same tab
If the link should load a new URL in the existing tab, do not wait for a popup. Pair the navigation wait and click in Promise.all() so the navigation listener is active before the click can trigger the navigation.
const [response] = await Promise.all([
page.waitForNavigation(),
page.locator('a.some-link').click(),
]);
console.log('Current URL:', page.url());
console.log('Navigation response:', response?.status() ?? 'no response');
Replace a.some-link with the page’s actual selector. Awaiting the click first and then calling waitForNavigation() can miss a quick navigation. This wait belongs to the page that changes URL; it does not capture a separate popup.
Find and switch to pages that are already open
await browser.pages() lists open pages across browser contexts. If you only want pages in one context, use await context.pages(). The standard page listings omit non-visible pages such as background pages, so they are not a complete inventory of every possible browser target.
const pages = await browser.pages();
console.log('Open pages:', pages.map(page => page.url()));
const contextPages = await page.browserContext().pages();
console.log('Pages in this context:', contextPages.map(page => page.url()));
Enumeration helps inspect the browser during debugging or work with known existing pages. Comparing the lists before and after a click can suggest which page is new, but that is a derived strategy rather than a stable identity mechanism. Page ordering is not a guarantee that the newest tab occupies a particular index. If you use enumeration, match on a reliable URL or other workflow condition and account for other pages being created concurrently.
Once you have the correct Page, switch the active tab with:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsawait pageToActivate.bringToFront();
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot missing popups and unexpected navigation
- The script hangs waiting for a popup: The link may navigate the existing page instead, the selector may identify the wrong element, or the site may block or conditionally suppress the popup. Check the expected behavior in the site and inspect the opener page’s URL after the click. Use
waitForNavigation()only if the current page is meant to navigate. - The popup opened, but your code missed it: Register the popup listener or target wait before clicking. If other code can create pages at the same time, constrain the wait with a reliable URL or workflow predicate.
- The wrong tab was selected: Do not treat array position as page identity. Inspect URLs and use a specific condition. Use
context.pages()when other contexts should not be part of the selection. - The locator cannot click the link: Confirm the selector matches the intended element and that the element is available and actionable. Prefer a locator that uniquely identifies the link instead of a broad selector matching several controls.
goto()did not throw, but the page returned an error status: In headless shell mode, valid HTTP responses such as 404 and 500 do not by themselves causegoto()to throw. Inspect the navigation response’s status when HTTP success matters to your workflow.- The navigation response is
null: Navigation toabout:blankor a same-URL hash change can returnnull. Do not treat a missing response object alone as proof that nothing happened; inspect the resulting URL and page state.
Performance, reliability, and cost considerations
Creating a new page and capturing a site-created popup both add browser work. Reuse a page when the workflow does not require another tab, and close pages you no longer need if your automation creates many of them. For reliability, make waits match the expected outcome and identify the page by a condition relevant to the task instead of relying on timing or list order. No general timing or performance figure applies to every site: load behavior, popup logic, and network conditions vary.
For a workflow that only needs a screenshot rather than interactive browser automation, a screenshot API may avoid maintaining Puppeteer browser setup. ScreenshotNeo is a website screenshot API and MCP server; its stated differentiators include removing known consent banners, newsletter popups, and chat widgets before capture, and charging only for clean shots rather than bot checks, blank pages, failed loads, timeouts, or cache hits. That is a different tool for a different job: it does not replace Puppeteer when your task needs to click links and switch among live pages.
Or skip the browser setup
If your goal is simply to capture a page, ScreenshotNeo can return a screenshot or PDF with one GET request. See the ScreenshotNeo API documentation for parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
Cookie and consent banners, popups, and chat widgets are removed before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server lets AI agents use screenshot tools, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create an account at ScreenshotNeo’s free sign-up page.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteFrequently asked questions
Does a popup belong to a different browser context?
No. A popup opened by a page belongs to its opener’s BrowserContext. Use the context’s page list when you need to inspect pages within that session boundary.
Should I use browser.newPage() or context.newPage()?
Use browser.newPage() for a page in the browser’s default context. Use context.newPage() when your code needs the page in a particular context.
Can I use this approach with a visible browser?
Yes. The popup and navigation patterns apply to Puppeteer pages in either headless or visible browser workflows. Use bringToFront() when you need to activate a page in a visible session.
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.

