Connect Puppeteer to a hosted browser with puppeteer.connect() and the browser provider’s WebSocket endpoint, rather than starting Chrome with puppeteer.launch(). For the Browserless managed-browser flow, install puppeteer-core, use the provider-issued wss:// URL (which includes its authentication token), and close the connection in a finally block. Once connected, familiar page APIs such as goto(), selectors, waits, evaluation, screenshots and PDFs continue to work. The important differences are the endpoint, session lifecycle, file system, browser defaults, network latency and concurrency accounting.
What changes when Puppeteer runs against a remote browser?
Puppeteer is a JavaScript library with a high-level API for automating Chrome and Firefox through Chrome DevTools Protocol (CDP) and WebDriver BiDi. A local script normally launches a browser binary on the same machine. Remote automation moves that browser to a managed host, container or another server and connects over a secure WebSocket.
| Concern | Local launch | Remote connection |
|---|---|---|
| Starting the browser | puppeteer.launch() starts a local executable. |
puppeteer.connect({ browserWSEndpoint }) attaches to an already-running browser. |
| Page automation | Navigation, selectors, waits and evaluation run locally. | The same page-level code generally works; commands cross the network. |
| Files | The browser and Node.js process can normally see the same local paths. | The browser host cannot see paths on your Node.js machine. Use the provider’s upload/download facilities. |
| Environment | Your installed browser and machine defaults apply. | Viewport, user agent, timezone and locale may be different and should be set deliberately. |
| Lifecycle | Closing the local browser ends the process. | browser.close() releases the remote session; an abandoned session can remain active until timeout and may incur provider charges. |
| Parallelism | Your machine controls process capacity. | Each connection is a provider session and counts toward its concurrency limit. |
The Browserless example below is provider-specific. Other services may use different endpoint paths, authentication parameters, browser options and file-transfer APIs.
Prerequisites and secure endpoint setup
- Node.js with ES module support (or adapt the import to your project’s module system).
- A remote-browser account and a provider-issued WebSocket endpoint.
- The provider’s current authentication and concurrency terms.
- A secret-management method such as environment variables; never commit a token-bearing URL.
For Browserless’s documented managed-browser flow, install the core client:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
npm install puppeteer-core
puppeteer-core does not download a Chromium binary, which is appropriate when the browser runs remotely. The full puppeteer package can also call connect(), but it downloads a local browser during installation even though the remote-only workflow does not need it.
Store the complete endpoint in an environment variable. Browserless documents a secure wss:// endpoint with a token query parameter. Do not print the variable, include it in source control, or log a full URL in an error message.
export BROWSER_WS_ENDPOINT='wss://provider.example/connect?token=YOUR_TOKEN'
The hostname, path and query parameters are illustrative placeholders: copy the exact endpoint format from your selected provider’s current documentation.
Minimal Node.js connection
This complete script attaches to the remote browser, creates one page, navigates to a URL and closes the remote session even if navigation or evaluation fails.
Crashes, 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 minuteWindows 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 reinstallimport puppeteer from 'puppeteer-core';
const endpoint = process.env.BROWSER_WS_ENDPOINT;
if (!endpoint) throw new Error('Set BROWSER_WS_ENDPOINT');
const browser = await puppeteer.connect({
browserWSEndpoint: endpoint,
});
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log(await page.title());
} finally {
await browser.close();
}
connect() returns a Puppeteer Browser object, so normal APIs such as newPage(), page.goto(), page.locator(), page.waitForSelector(), page.evaluate(), page.screenshot() and page.pdf() remain available. The network is now between your Node.js process and the browser host, so every operation should be written with realistic timeouts and error handling.
Set browser conditions explicitly
Viewport and device scale
Remote providers may use a different default viewport or device scale than your laptop. Set them before navigation when screenshots, responsive layouts or visual tests must be repeatable.
Rank #2
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
User agent, locale and timezone
Sites can serve different markup, language, date formats or experiments based on these values. Configure them to match the environment you are testing rather than assuming the remote host matches your workstation.
await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/131 Safari/537.36');
await page.emulateTimezone('America/New_York');
await page.setExtraHTTPHeaders({ 'Accept-Language': 'en-US,en;q=0.9' });
Use a provider region geographically close to the sites under test. This reduces the distance between the browser and target site; the distance between your script and the browser still affects command round trips.
Authentication and cookies
Credentials belong to the remote browser context, not your local file system. Set them through Puppeteer or the provider’s documented session options, and avoid embedding secrets in page URLs.
await page.setCookie({
name: 'session',
value: process.env.TEST_SESSION,
domain: 'example.com',
path: '/',
secure: true,
httpOnly: true,
});
Files, downloads and uploads
A remote browser cannot read /Users/alex/project/file.pdf on your laptop. A path passed to an upload control must exist on the browser host, or the provider must expose a transfer mechanism. Likewise, a download is created remotely and must be retrieved through the provider’s download API or a browser-side transfer flow.
Design file handling as an explicit boundary:
- Upload input data using the hosting service’s documented upload mechanism, object storage or a data stream.
- Set the remote page’s file input to the path that exists in the remote session.
- Wait for the download event and save or transfer the resulting remote file according to the provider’s API.
- Delete temporary remote files when the provider does not clean them up automatically.
Do not rely on relative paths, shared mounts or temporary directories being identical between machines.
Browser options and provider query parameters
With a local launch, options such as executable flags are passed to launch(). In a managed service, the browser may start before your client connects, so the provider may require launch settings in endpoint query parameters. Browserless documents this pattern for its managed browser. Follow that provider’s syntax exactly; array-valued options may need JSON encoding before they are placed in a URL.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsKeep endpoint construction separate from application logic, validate allowed options, and redact the resulting URL from logs. A malformed query string can produce a browser with unexpected flags or fail before Puppeteer connects.
Sessions, cleanup and concurrency
Always close the remote session
Put browser.close() in finally, not only after the success path. Browserless states that closing ends the remote session; an unclosed session can stay active until a timeout and may accrue billing.
let browser;
try {
browser = await puppeteer.connect({ browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT });
const page = await browser.newPage();
await page.goto('https://example.com', { timeout: 45_000, waitUntil: 'networkidle2' });
} catch (error) {
console.error('Remote automation failed:', error.message);
process.exitCode = 1;
} finally {
if (browser) await browser.close().catch(() => {});
}
Reuse one connection inside a job
Each Puppeteer connection is a provider session. Open several pages from one browser for a single workflow instead of connecting repeatedly:
const browser = await puppeteer.connect({ browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT });
try {
const [catalog, checkout] = await Promise.all([
browser.newPage(),
browser.newPage(),
]);
await Promise.all([
catalog.goto('https://example.com/catalog'),
checkout.goto('https://example.com/checkout'),
]);
} finally {
await browser.close();
}
Use separate connections for parallel jobs
Independent jobs should use separate provider connections when isolation is required, but every connection consumes concurrency. Bound your worker pool to the plan’s documented limit and close each connection when its job ends. Do not assume opening many pages bypasses a provider’s session limit.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Reliability and performance practices
- Choose
waitUntilbased on the page:domcontentloadedis often sufficient for static DOM work, whilenetworkidle2waits longer on applications with continuing requests. - Use explicit navigation, selector and overall job timeouts. A remote command can fail because the target is slow, the browser session ended, or the network path dropped.
- Retry only safe, idempotent operations. Repeating a form submission can create duplicate side effects.
- Record a job identifier, target URL without secrets, elapsed time, and the final error class. Never record token-bearing endpoints, passwords or session cookies.
- Keep the browser near target sites and the Node.js worker near the browser when command latency matters.
- Reuse pages within a controlled job, then close the browser so idle sessions do not consume capacity.
Troubleshooting remote Puppeteer
“Invalid URL” or connection refused
Confirm that the value is a WebSocket endpoint beginning with wss:// (or the provider’s documented secure alternative), not an HTTPS dashboard or website URL. Check DNS, firewall egress and the provider’s endpoint region.
Authentication or unauthorized errors
Use the provider’s current token parameter and an unexpired credential. Browserless documents a token query parameter, but another service may use a header or a different query name. Rotate a leaked token and remove it from logs and shell history.
Rank #4
The page looks different from local Chrome
Compare viewport, user agent, timezone and locale first. Then compare browser version, cookies, geolocation and feature flags. Remote defaults are not guaranteed to match your development machine.
Uploads or downloads fail
The path probably exists only on the Node.js host. Transfer the file using the provider’s supported mechanism, or use a remote object-storage URL and verify permissions.
Free tools Windows power users keep installed
One-click scans. No signup required.
Jobs hang or sessions accumulate
Check that every code path reaches finally, including rejected promises and process shutdown. Add bounded timeouts and inspect provider session status. An unclosed remote session may remain active until timeout.
Parallel work is rejected
You may have exceeded the provider’s concurrency limit. Reuse one connection for pages in one job, queue additional jobs, or select a plan with the required documented concurrency.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.When local launch is still the better choice
Use puppeteer.launch() when you need offline development, direct control of the installed browser and flags, local files without transfer, or a simple single-machine test. Use a remote browser when CI workers should not install or maintain Chrome, when a managed region is closer to target sites, or when you need browser capacity separate from your application host. Compare browser-version control, file-transfer requirements, network distance, concurrency limits and the provider’s current terms before choosing.
Or skip the browser setup
If your goal is a clean website image or PDF rather than arbitrary browser interaction, ScreenshotNeo provides a one-call screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
Use the API directly:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent 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}`);
And 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)
See the ScreenshotNeo API documentation for PNG, JPEG, WebP and PDF options, full-page and selector captures, device presets, custom CSS and JavaScript, waits, request blocking, headers, cookies, geolocation, caching, signed links, asynchronous webhooks, bulk capture and usage reporting. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Best Value
- Used Book in Good Condition
The Free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I use the full puppeteer package instead of puppeteer-core?
Yes. The full package can call puppeteer.connect(), but it downloads a local Chromium binary during installation. puppeteer-core avoids that download for a remote-only workflow.
Is a remote browser endpoint the same as an HTTP API URL?
No. Puppeteer expects the provider’s WebSocket endpoint, normally beginning with wss://. An HTTPS dashboard or ordinary page URL will not work with browserWSEndpoint.
Do multiple pages require multiple remote connections?
No. Pages in one job can share a single connected Browser object. Separate connections are appropriate for independently isolated parallel jobs and count separately toward provider concurrency.
Who controls the browser version in a managed service?
The hosting provider normally controls the remote browser image or offers documented version choices. Verify the provider’s current browser-version and launch-option support when reproducibility is essential.
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.




