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 & 11Outdated 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 match“Puppeteer is not a constructor” usually means your code is instantiating the wrong export in the wrong runtime. In Node.js, do not call new Puppeteer(): the package exports a configured PuppeteerNode instance, whose methods include launch() and connect(). In a browser page or Chrome extension, the Node package import is not a browser bundle. Build a browser-compatible bundle from the browser entry point in puppeteer-core, then connect to an existing browser endpoint or extension transport.
The correct fix therefore depends on whether the failing file runs in Node, a regular web page, or an extension background/service-worker context.
What the error actually means
Puppeteer’s common API is represented by a class, but its constructor is internal. The official API reference says third-party code should not call that constructor directly or create subclasses from it. Application code should use the exported object and its methods instead.
In Node.js, require('puppeteer') or an ES-module import gives you a PuppeteerNode instance. That class extends the shared Puppeteer API, so this is the normal pattern:
#1 Best Overall
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log(await page.title());
await browser.close();
})();
This is different from new Puppeteer(). Renaming the variable does not change what was imported; inspect the value and the package resolution if you are unsure.
First identify the runtime
| Runtime | Use this entry point | How a browser connection is made | Important limitation |
|---|---|---|---|
| Node.js script, server, or test runner | puppeteer (or puppeteer-core when you manage Chrome yourself) |
launch() starts a browser, or connect() attaches to a WebSocket endpoint |
Normal Node APIs are available |
| Ordinary browser page | Browser-compatible bundle built from puppeteer-core/lib/puppeteer/puppeteer-core-browser.js |
connect() to a valid browser WebSocket endpoint |
The page cannot spawn a local Chrome process |
| Chrome extension | The browser entry point from puppeteer-core, bundled for the extension |
ExtensionTransport.connectTab(tab.id) through chrome.debugger |
Support is experimental; one connection represents one page |
If the stack trace names puppeteer-web.js, a background page, service worker, or extension bundle, treat it as a browser-runtime problem rather than a normal Node import problem.
Fix a Node.js project
Use the exported instance
Replace constructor calls with method calls on the imported value:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
With CommonJS:
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
Attach instead of launching
If Chrome is already running with remote debugging enabled, use connect() and the complete WebSocket endpoint:
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
const puppeteer = require('puppeteer');
const browser = await puppeteer.connect({
browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT
});
const pages = await browser.pages();
console.log(`Connected to ${pages.length} page(s)`);
await browser.disconnect();
Use disconnect() when Puppeteer should leave the externally managed browser running; use close() only when Puppeteer owns the process.
Check what was imported
Temporary diagnostics can reveal an import or bundler mistake:
const imported = require('puppeteer');
console.log(typeof imported, Object.keys(imported));
console.log(typeof imported.launch, typeof imported.connect);
You should see callable launch and/or connect methods. If you see a module namespace containing a default property, your transpiler may require import puppeteer from 'puppeteer' or require('puppeteer').default; use one module system consistently rather than mixing both forms.
Fix a normal browser page
A browser cannot use the Node package import as a substitute for a browser bundle. Bundle the browser-specific entry point from puppeteer-core with your build tool, then call connect() from that bundle. The browser must already expose a valid DevTools WebSocket endpoint.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Rank #3
import puppeteer from 'puppeteer-core/lib/puppeteer/puppeteer-core-browser.js';
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:9222/devtools/browser/REPLACE_WITH_ID'
});
const pages = await browser.pages();
console.log(pages.length);
await browser.disconnect();
Do not put a Node-only launch() call in page JavaScript: process creation, filesystem access, and other Node facilities are unavailable in the web sandbox. Keep the endpoint private; exposing a debugging WebSocket to untrusted origins gives them powerful control over the browser.
Fix a Chrome extension
Puppeteer’s extension guide describes this path as experimental because extensions receive restricted Chrome DevTools Protocol access through chrome.debugger. Build the extension with a bundler, import the browser entry point from puppeteer-core, request the permissions required by your manifest, and connect through ExtensionTransport.
import puppeteer from 'puppeteer-core/lib/puppeteer/puppeteer-core-browser.js';
import { ExtensionTransport } from 'puppeteer-core/lib/puppeteer/web.js';
const tab = await chrome.tabs.create({ url: 'https://example.com' });
const transport = await ExtensionTransport.connectTab(tab.id);
const browser = await puppeteer.connect({ transport });
const pages = await browser.pages();
console.log(pages.length);
await browser.disconnect();
Exact import paths can vary with the installed Puppeteer release and bundler exports, so verify the paths resolved in your project rather than copying a Node path into the extension. The key requirements are the browser-compatible entry point and ExtensionTransport.connectTab(tab.id).
The one-page limitation
In the documented extension setup, a connected Puppeteer browser represents one page. To work with another tab, create or locate it with chrome.tabs, then establish another transport connection for that tab. Do not assume browser.newPage() behaves like it does in a normal Node-launched browser.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →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
Manifest and bundling checks
- Bundle the extension code before loading it; a raw Node package import is not a browser bundle.
- Grant only the permissions your extension needs, including the debugger permission required by your chosen flow.
- Ensure the background page or service worker loads the generated bundle, not source files containing unresolved Node imports.
- Inspect the generated bundle for duplicate Puppeteer copies or a resolver selecting a Node entry point.
Why the old unsafe-eval advice is not a default fix
A 2018 Chrome 69 extension question reported this error after loading puppeteer/utils/browser/puppeteer-web.js. Its accepted answer suggested changing extension policy to allow unsafe-eval. That answer belongs to the reported historical environment. Current Puppeteer guidance instead uses a browser-specific bundle and extension transport; the old manifest change is not established here as a general, present-day remedy.
Systematic troubleshooting
“Puppeteer” is undefined or has no launch method
- Cause: An incorrect default/named import or CommonJS/ES-module interop mismatch.
- Fix: Log the imported object, then use the syntax matching your module system. Confirm that
typeof puppeteer.launchis'function'in Node.
The error appears only after bundling
- Cause: The bundler resolved the Node entry point, removed a browser export, or included multiple incompatible builds.
- Fix: Import the documented browser entry point explicitly, inspect the bundle’s module resolution, and rebuild after clearing stale output.
launch() fails in a web page or extension
- Cause: Browser JavaScript cannot start a local process.
- Fix: Start Chrome elsewhere and use
connect(), or use the extension transport for a tab.
connect() reports an invalid endpoint
- Cause: The value is an HTTP URL, a page-level target URL, truncated, or no longer valid.
- Fix: Supply the complete browser WebSocket endpoint and verify that the debugging browser is reachable from the runtime.
The extension connects but controls the wrong tab
- Cause: The tab ID used for transport is stale or belongs to another tab.
- Fix: Query the current tab with
chrome.tabs, wait for navigation as needed, and callconnectTab()with that tab’s current ID.
It works in Node but not in the extension
- Cause: Different runtime assumptions, permissions, CSP, or package entry-point resolution.
- Fix: Compare the actual runtime, generated bundle, installed package tree, manifest permissions, and full stack trace. A Node success does not validate an extension bundle.
Performance, reliability, and security considerations
Reuse one browser connection for multiple operations when the runtime permits it, and close or disconnect deterministically. In extensions, account for tab lifecycle events: tabs can close or navigate while a protocol session is active. Keep debugging endpoints and extension permissions private, and avoid logging authentication headers, cookies, or full WebSocket URLs.
Do not diagnose from the exception text alone. Record the runtime, package version, exact import statement, bundler configuration, generated entry point, manifest permissions, and complete stack trace. Those details distinguish an internal-constructor mistake from a browser-bundle or transport failure.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your goal is simply to obtain a reliable website screenshot rather than operate Puppeteer inside a page or extension, ScreenshotNeo provides a single HTTP request. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with the result identified by response headers. Its MCP server lets Claude, Cursor, or another MCP client use take_screenshot, get_page_info, and capture_pdf.
Use the complete API documentation at https://screenshotneo.com/docs/. cURL:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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 includes 1,000 screenshots each month free with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I fix this by changing new Puppeteer() to new puppeteer()?
No. The normal Node export is already an instance. Call puppeteer.launch() or puppeteer.connect(); do not instantiate the internal class.
Does this error prove that Puppeteer is not installed?
No. It more often indicates an incorrect export, runtime, or bundle. Check the resolved package and imported methods before reinstalling.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Can an extension create unlimited Puppeteer pages after connecting?
Not with the documented extension flow. Each connected browser represents one page; use chrome.tabs and another connection for an additional tab.
The Bottom Line
Use the exported Puppeteer instance in Node. For a browser page or extension, bundle the browser entry point from puppeteer-core and connect through the appropriate WebSocket or ExtensionTransport; do not rely on the historical unsafe-eval workaround.
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.




