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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Set the proxy at the layer that creates the browser session. With a hosted Browserless endpoint, add your proxy as the externalProxyServer query parameter. With native Playwright, pass server, username, and password to browser.newContext(). With self-hosted Browserless, add Chromium’s --proxy-server flag to the WebSocket URL. The scope matters: a launch-level proxy and a context-level proxy are not interchangeable, especially when using Chrome DevTools Protocol (CDP).

This guide shows the complete patterns, authenticated credentials, geographic and sticky-session options, verification steps, failure recovery, and the operational trade-offs of residential, datacenter, hosted, and self-hosted proxies.

Choose the proxy scope before writing code

A proxy can be applied when the remote browser launches or when an individual browser context is created. Those scopes determine which pages share an egress IP and which contexts can use different proxies.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Connection or deployment Where to configure the proxy Important behavior
Browserless hosted API externalProxyServer query parameter Works in both native Playwright and CDP connection modes; third-party proxy use requires a paid cloud-unit plan. Free plans reject it with HTTP 401.
Native Playwright connection browser.newContext({ proxy: ... }) Each context can have its own proxy and credentials.
Playwright over CDP Launch/query settings, or the default context The default context carries launch-level settings. A newly created context does not inherit those settings.
Self-hosted Browserless Docker Chromium --proxy-server flag in the WebSocket URL Browserless does not bundle a proxy server; you supply and operate one.

Use a URL in the form http://[username:password@]host:port or https://[username:password@]host:port. If a username or password contains @, :, /, ?, #, or another reserved character, percent-encode it before placing it in a connection URL.

Browserless hosted API: pass an external proxy

Browserless documents externalProxyServer for routing a session through a proxy you provide. The complete WebSocket pattern is:

wss://production-sfo.browserless.io?token=YOUR_TOKEN&externalProxyServer=http%3A%2F%2Fuser%3Apass%40proxy.example.com%3A8080

The value after externalProxyServer= is URL-encoded. In decoded form it is http://user:[email protected]:8080. Build this string programmatically rather than concatenating unescaped credentials:

const proxy = 'http://user:[email protected]:8080';
const endpoint = 'wss://production-sfo.browserless.io?token=' +
  encodeURIComponent('YOUR_TOKEN') +
  '&externalProxyServer=' + encodeURIComponent(proxy);

Omit the proxy parameter when you want direct egress through the host’s own IP. Browserless states that third-party proxy use is available on paid cloud-unit plans; a free plan returns 401 for this option.

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

Playwright: configure an authenticated proxy

Native Playwright connection

For a native Playwright connection, create the context with the proxy object. This keeps the proxy at context scope, so separate contexts can use different egress routes.

import { chromium } from "playwright-core";

const browser = await chromium.connectOverCDP(
  "wss://production-sfo.browserless.io?token=YOUR_TOKEN"
);

const context = await browser.newContext({
  proxy: {
    server: "http://proxy.example.com:8080",
    username: "username",
    password: "password"
  }
});

const page = await context.newPage();
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
console.log(await page.title());
await browser.close();

The server value contains the scheme, host, and port. Keep credentials in environment variables or a secret manager in production; do not commit them to source control or print the full connection URL in logs.

Rank #2

CDP inheritance gotcha

The example above uses Browserless’s CDP endpoint, but CDP has a significant scope rule: Browserless opens a default context that carries launch-level settings. If you need that launch-level proxy, use the existing default context instead of creating a new one:

const browser = await chromium.connectOverCDP(
  "wss://production-sfo.browserless.io?token=YOUR_TOKEN&externalProxyServer=http%3A%2F%2Fuser%3Apass%40proxy.example.com%3A8080"
);

const defaultContext = browser.contexts()[0];
const page = await defaultContext.newPage();
await page.goto("https://example.com");

A newly created CDP context may bypass the launch-level proxy. Native Playwright connections support multiple independent contexts with context-level proxy settings; CDP is Chromium-only and exposes the default-context behavior described above.

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

Puppeteer: use the connection or Chromium flags

Hosted Browserless connection

Pass the same Browserless query parameter through Puppeteer’s WebSocket connection:

import puppeteer from "puppeteer-core";

const browser = await puppeteer.connect({
  browserWSEndpoint:
    "wss://production-sfo.browserless.io?token=YOUR_TOKEN&externalProxyServer=http%3A%2F%2Fuser%3Apass%40proxy.example.com%3A8080"
});

const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
console.log(await page.title());
await browser.close();

Environment variables are not a universal browser proxy

Puppeteer’s configuration guide lists HTTP_PROXY, HTTPS_PROXY, and NO_PROXY for downloading and running the browser. Those variables do not automatically configure every page request, and puppeteer-core ignores Puppeteer configuration files and environment variables. For a remote Browserless session, use the connection/query setting or the provider’s launch configuration explicitly.

Self-hosted Browserless Docker

The open-source deployment does not include a proxy service. Supply your own proxy and pass Chromium’s flag for the session. Puppeteer example:

const browser = await puppeteer.connect({
  browserWSEndpoint:
    "ws://localhost:3000?token=YOUR_TOKEN&--proxy-server=http://proxy.example.com:8080"
});

const page = await browser.newPage();
await page.goto("https://example.com");

The same --proxy-server query pattern works when connecting to a self-hosted Browserless instance with Playwright over CDP. Treat custom Chromium arguments cautiously: Playwright warns that unsupported arguments can break browser functionality. Add one flag at a time and remove it if a session stops launching.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Residential, datacenter, geography, and session choices

Residential versus datacenter routing

Route Browserless documented rate Detection and cost trade-off
Residential 6 units/MB Described by Browserless as harder to detect, but costs more units.
Datacenter 2 units/MB Lower unit cost, but more easily detected.

These are provider-documented rates, not an independent benchmark. Choose residential routing when the target’s reputation checks are the problem; choose datacenter routing when predictable cost is more important and the target accepts it.

Country, city, and locale

proxyCountry accepts an ISO country code. proxyCity targets a city, but Browserless documents that city-level targeting requires a Scale plan with at least 500,000 units. proxyLocaleMatch can align browser language and formatting with the proxy location, reducing an obvious mismatch between IP geography and locale.

Keeping an IP stable

Plain REST and WebSocket requests use a random proxy node by default. Add proxySticky=true when you need the same IP where possible, such as a multi-step flow that expects session continuity. “Sticky” is a routing request, not a guarantee that an IP can never change.

Verify the egress path before testing the target

  1. Start with a clean session. Close old pages and create the context or connection with the intended proxy settings.
  2. Visit an IP-inspection page. Read the reported public address from inside the browser. Browserless’s examples use an IP-inspection page for this check.
  3. Compare the result with the expected proxy location. Confirm country, city (if requested), and whether the address belongs to the expected network.
  4. Only then open the target site. This separates proxy authentication and routing failures from target-site blocks.
  5. Record the verdict safely. Log a request identifier and high-level outcome, not the proxy password or complete signed WebSocket URL.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common failures

HTTP 401 when using an external proxy

Cause: Browserless requires a paid cloud-unit plan for third-party proxy use. Fix: confirm the account’s plan and units, or remove externalProxyServer when direct egress is acceptable.

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.

Proxy authentication fails

Cause: wrong credentials, a malformed scheme, or reserved characters that were not encoded. Fix: test the proxy URL independently, encode the username and password, and verify the host and port. In a query string, encode the complete proxy URL rather than only the password.

The browser shows the original IP

Cause: the setting was applied at the wrong scope. Fix: use browser.newContext({ proxy }) for native Playwright, the Browserless query parameter for hosted sessions, or --proxy-server for self-hosted Chromium. In CDP mode, use browser.contexts()[0] when relying on launch-level inheritance.

A newly created CDP context bypasses the proxy

Cause: launch-level settings are attached to Browserless’s default context, not automatically copied to a new context. Fix: use the default context, or switch to a native Playwright connection and set a context-level proxy explicitly.

Puppeteer environment variables have no effect

Cause: you are using puppeteer-core, which ignores Puppeteer configuration files and environment variables, or you expected download settings to proxy page traffic. Fix: configure the remote connection or Chromium launch directly.

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

Custom flags make Playwright unstable

Cause: an unsupported Chromium argument conflicts with Playwright. Fix: remove nonessential flags, retain only the proxy argument, and add options back individually while checking that the browser still launches.

Performance, reliability, and cost considerations

  • Bandwidth is a direct cost driver. Browserless documents 6 units/MB for residential routing and 2 units/MB for datacenter routing, so large pages, media, and repeated retries consume more units.
  • Proxy distance affects latency. A city or country route farther from the target or browser region can add connection time. Match geography only when the application needs it.
  • Sticky routing helps workflows, not throughput. Reusing an IP can reduce authentication surprises in a multi-step flow, while random nodes may distribute load across requests.
  • Separate browser failures from proxy failures. An IP-inspection request before the target gives you a cheap, reproducible health check.
  • Self-hosting shifts the burden. You control the Browserless container and proxy relationship, but you must supply the proxy, secure credentials, monitor availability, and handle rotation yourself.

Or skip the browser setup

If your requirement is a clean website screenshot rather than an interactive browser session with your own egress IP, ScreenshotNeo provides a one-request screenshot API. It removes cookie and consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

See the parameter reference in the ScreenshotNeo documentation. 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 full-page and element captures, device presets, custom CSS and JavaScript, waits, request blocking, PDF output, signed links, asynchronous jobs, bulk capture, and caching. It does not replace a proxy-controlled interactive session; use the Browserless patterns above when the target must see your proxy IP.

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

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots, and every feature is included on every plan. Create a free ScreenshotNeo account.

FAQ

Frequently Asked Questions

How should proxy credentials be handled in CI?

Store them in the CI platform’s encrypted secrets, construct the connection URL at runtime, and redact WebSocket URLs and proxy values from logs. Rotate credentials independently of application code.

Can I use one proxy for some pages and another for others?

Yes with native Playwright: create separate browser contexts and give each context its own proxy object. Do not assume a newly created CDP context inherits launch-level settings; use the default context or a native connection.

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.

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