List Browser Targets with Puppeteer
Use Puppeteer’s `browser.targets()` to list active targets across contexts, inspect their types, and choose the right API for pages or one context.
Use await browser.targets() to get a Target[] containing active Puppeteer targets across all browser contexts. Each target can be inspected with target.type() and target.url(). To restrict results to one context, use context.targets(). If you only need page objects, use browser.pages() or context.pages(), keeping in mind that page lists omit some non-visible targets.
List every active browser target
This runnable example launches Chromium, opens a page, prints every browser-wide target, then closes the browser. Install Puppeteer with npm install puppeteer; the package downloads a compatible browser by default.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const targets = await browser.targets();
for (const target of targets) {
console.log({ type: target.type(), url: target.url() });
}
} finally {
await browser.close();
}
})();
In an existing Puppeteer program, the essential call is simply:
const targets = await browser.targets();
Each entry is a Puppeteer Target object, not a Page. Use target.page() when you need a page handle for a page-like target; it can resolve to null for target kinds that do not expose a page.
Choose the right enumeration method
| Method | Scope | What it returns | Use it when |
|---|---|---|---|
browser.targets() |
All browser contexts | Active Target[] |
You need browser-wide target discovery, including non-page targets. |
context.targets() |
One BrowserContext |
Active Target[] in that context |
You need to inspect an isolated session without mixing in other contexts. |
browser.pages() |
All contexts | Page objects | You want open pages rather than every target category. |
context.pages() |
One context | Page objects | You want pages in a single isolated session. |
pages() is not a complete substitute for target enumeration: non-visible page-like targets, such as background pages, may not be included. Use Target.page() where a page object is needed for a particular target.
Filter targets by type
Call target.type() to branch on the documented target category. Puppeteer documents these values: background_page, browser, other, page, service_worker, shared_worker, and webview. Target kinds available in practice depend on the browser and what is running.
const targets = await browser.targets();
const pages = targets.filter(target => target.type() === 'page');
const workers = targets.filter(target =>
['service_worker', 'shared_worker'].includes(target.type())
);
for (const target of pages) {
console.log('Page target:', target.url());
}
for (const target of workers) {
console.log('Worker target:', target.type(), target.url());
}
To obtain a page handle only when one is available:
for (const target of await browser.targets()) {
const page = await target.page();
if (page) {
console.log('Page handle for:', target.url());
}
}
Do not assume every target has a non-empty URL or produces a page object. Check the type and the result of target.page() before using page methods.
Limit the list to one browser context
Contexts isolate browser state such as cookies and storage. A newly launched browser has at least a default context. Create another context when you need an isolated session, then enumerate its targets directly:
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://example.com');
const contextTargets = await context.targets();
for (const target of contextTargets) {
console.log(target.type(), target.url());
}
Use browser.targets() when the scope should include that context and every other context. Use context.targets() when results must stay scoped to a single context.
Wait for targets that appear later
browser.targets() reports targets active at the time you call it. If an action opens a new page or worker asynchronously, a one-time list can run too early. Wait for the expected target event and then inspect the resulting target.
const targetPromise = browser.waitForTarget(
target => target.type() === 'page' && target.url().includes('/report')
);
await page.click('a.open-report');
const reportTarget = await targetPromise;
console.log(reportTarget.url());
Use an appropriate timeout for the workflow and handle timeout errors if the target is optional. Avoid polling in a tight loop; it adds work without making target creation faster.
Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| A target is missing from the list. | It has not been created yet, or it closed before enumeration. | Wait for the action that creates it; use browser.waitForTarget() for an asynchronous target. |
A background page does not appear in pages(). |
pages() returns page objects and omits some non-visible targets. |
Use browser.targets() or context.targets(), then inspect target.type(). |
target.page() returns null. |
The target is not represented by a Puppeteer Page, or is not a page target. |
Check the type first and only call page methods when a page handle exists. |
| The same URL appears more than once. | Different targets can share a URL, or the target list spans multiple contexts. | Use target type and context scope as well as URL when identifying a target. |
browser.targets is not a function. |
The variable may not be a Puppeteer Browser, or the installed package/version differs from the code assumptions. |
Check the object returned by puppeteer.launch() or puppeteer.connect() and consult the API reference matching your installed version. |
Performance, reliability, and version notes
Target listing is a browser inspection operation, not a page load. The practical work around it usually comes from launching the browser, waiting for target creation, or taking action on each target. Keep enumeration scoped with context.targets() when that is all you need, and avoid repeatedly scanning in a tight polling loop.
Target lists are snapshots: browser activity can change immediately after the call. If correctness depends on a target appearing or disappearing, use Puppeteer’s target lifecycle or wait APIs and include timeouts and cleanup in the surrounding workflow. Target categories and API details can vary with Puppeteer releases; check the documentation for the version installed by your project.
Or skip the browser setup
If the goal is a clean screenshot rather than inspecting Puppeteer targets, ScreenshotNeo returns an image or PDF from one API request. See the API documentation for options and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free.
FAQ
Does browser.targets() include targets from incognito contexts?
Yes. Its scope covers active targets across the browser’s contexts. Use context.targets() if you want just one context.
Is a Puppeteer target the same as a tab?
No. A target can represent a page, worker, browser target, or another documented category. Inspect target.type() to determine which kind you have.
What should I use to list only open pages?
Use browser.pages(), or context.pages() for one context. Choose target enumeration when non-visible or non-page targets matter.
Can I rely on the target list staying current?
No; it reflects active targets when called. For targets created by later actions, wait for the relevant target instead of relying on an earlier snapshot.


