October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
browser automation

How to Fix “Puppeteer Is Not a Constructor” in puppeteer-web

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
HTML and CSS: Design and Build Websites
  • 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • 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.launch is '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 call connectTab() 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.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the complete API documentation at https://screenshotneo.com/docs/. cURL:

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.