The One Thing Most Browserless Proxy Guides Get Wrong
Because Browserless drives Chromium, people assume they set the proxy the way they would locally — a --proxy-server launch flag plus a page.authenticate call inside the session. But you don't control the launch args of a browser running on someone else's infrastructure. The proxy has to be declared when you connect, not after.
Browserless handles this with a query parameter on the connect URL:
...?token=TOKEN&externalProxyServer=<your-url-encoded-endpoint>
Put your German mobile endpoint — credentials and all — into externalProxyServer, URL-encoded, and Browserless routes the whole session through it. No launch flag inside your code, no separate authenticate step: the connect string carries everything.
With a dedicated German mobile endpoint you also skip the per-request rotation logic that pool-based setups need — one endpoint on the connect string, and you rotate on demand at the proxy when you choose to.
Before You Start
You need four values from your GermanProxy.io account, plus your Browserless token:
- Host and port of your endpoint
- Username and password
- Your Browserless API token (external proxies require a paid plan; free tiers return
401)
The examples use PROXY_HOST, PORT, USER, PASS and TOKEN as placeholders — replace them with your own. Install whichever client you already use:
npm install puppeteer-core
# or
npm install playwright-core
puppeteer-core / playwright-core is enough — Browserless runs the actual browser, so you don't need a bundled Chromium locally.
Step 1 — Build the Connect URL With externalProxyServer
Your endpoint goes into the connect string as a URL-encoded value. Credentials sit inline as USER:PASS@:
// From your GermanProxy.io account
const PROXY_HOST = "PROXY_HOST";
const PORT = "PORT";
const USER = "USER";
const PASS = "PASS";
const TOKEN = "TOKEN"; // Browserless API token
// Encode the whole endpoint so :// @ : survive as a query value
const proxyUrl = encodeURIComponent(
`http://${USER}:${PASS}@${PROXY_HOST}:${PORT}`
);
encodeURIComponent is not optional here: the endpoint is a URL living inside another URL, so its ://, @ and : must be escaped or the connect string won't parse.
Step 2 — Connect With Puppeteer
Point puppeteer.connect at the Browserless WebSocket endpoint with your token and the encoded proxy:
const puppeteer = require("puppeteer-core");
(async () => {
const browserWSEndpoint =
`wss://production-sfo.browserless.io?token=${TOKEN}` +
`&externalProxyServer=${proxyUrl}`;
const browser = await puppeteer.connect({ browserWSEndpoint });
const page = await browser.newPage();
await page.goto("https://www.example.de", { waitUntil: "domcontentloaded" });
console.log("Title:", await page.title());
await browser.close();
})();
Every request from that session — HTML, XHR, fetch, images — now travels over your German mobile IP. Because the credentials are inline in externalProxyServer, you do not add a separate page.authenticate call for the external proxy.
Step 3 — Connect With Playwright
The same parameter works from Playwright; only the connect call differs:
const { chromium } = require("playwright-core");
(async () => {
const endpoint =
`wss://production-sfo.browserless.io/chromium/playwright?token=${TOKEN}` +
`&externalProxyServer=${proxyUrl}`;
const browser = await chromium.connect(endpoint);
const page = await browser.newPage();
await page.goto("https://www.example.de", { waitUntil: "domcontentloaded" });
console.log("Title:", await page.title());
await browser.close();
})();
Same endpoint, same query parameter — externalProxyServer lives on the connect URL, so it's library-agnostic. Confirm your account's exact host and Playwright connect path in your Browserless dashboard; the token and proxy parameter are the constant part.
Step 4 — Verify the IP Before You Scale
Confirm the session is actually on a German mobile IP before you build anything on top of it. Point the page at an IP-echo endpoint and read the result:
await page.goto("https://api.ipify.org?format=json", {
waitUntil: "domcontentloaded",
});
const ip = await page.evaluate(() => document.body.innerText);
console.log("Egress IP:", ip);
If it returns a Browserless datacenter address instead of your German mobile IP, the externalProxyServer value isn't reaching the session — re-check that it's URL-encoded and appended with &, not lost in an unescaped ://. A 400 here usually means an external proxy was combined with a built-in proxy= option; a 401 means the plan doesn't allow external proxies. For a fuller checklist, see test your mobile proxy setup, and for credential issues, how to fix 407 proxy authentication required.
Step 5 — Check for WebRTC and DNS Leaks
The proxy routes the remote browser's HTTP traffic, but two side channels can still expose a real address:
- WebRTC can surface an IP via ICE candidates even with a proxy set — see what a WebRTC leak is.
- DNS can resolve names outside the tunnel depending on configuration — see what a DNS leak is.
For headless data-collection work WebRTC is usually inert, but verify it for any flow where IP consistency matters. A real German mobile IP only helps if nothing else leaks past it.
HTTP vs. SOCKS5 Through Browserless
Both protocols come with your endpoint. Which you put in externalProxyServer depends on what you need:
| Aspect | HTTP endpoint | SOCKS5 endpoint |
|---|---|---|
| Value in externalProxyServer | http://USER:PASS@HOST:PORT |
socks5://HOST:PORT |
| Username/password auth in Chromium | Yes — inline in the encoded URL | No — Chromium has no SOCKS5 user/pass auth |
| Best auth mode | Credentials | IP allowlist |
| Typical use | Default for most scraping | Lower-level / non-HTTP traffic |
For most Browserless scraping, the HTTP endpoint with inline credentials is the simplest path. SOCKS5 works when you can use IP-allowlist authentication, since the underlying Chromium can't authenticate a SOCKS5 proxy with a username and password. Background: SOCKS5 vs HTTP proxy.
Sticky Sessions vs. Rotation
With a dedicated German endpoint you control the IP at the proxy, not in your Browserless calls:
- Sticky session: keep one connected browser open across a multi-step flow — login, navigate, paginate — and the German mobile IP stays the same.
- Rotation on demand: when you want a fresh IP, trigger rotation at the proxy and open a new connection. There's no per-request IP pool to juggle in the connect string.
This is why a dedicated endpoint keeps the connect logic small: no rotation list, no health-checking, no retry-on-dead-IP loop. See sticky sessions and IP rotation explained and dedicated vs shared mobile proxy.
Why a Mobile IP for Browserless at All
Browserless runs headless Chromium for you, which is a common choice for JavaScript-heavy pages a plain HTTP client can't render. But by default the session exits from a Browserless datacenter IP, and datacenter ranges are widely distrusted — so even a well-behaved crawler can hit friction. Routing the session through a real German mobile IP changes the egress: it rides on carrier-grade NAT (CGNAT), the same shared-IP space thousands of ordinary phone users sit behind, which is why it carries higher IP reputation on German platforms.
For the trade-offs against other IP types, see mobile vs residential vs datacenter proxy and what is a mobile proxy. Running an autonomous agent instead of a scraper? See mobile proxies for AI agents.
Scrape Responsibly
A mobile proxy improves reliability for legitimate data collection — it is not a tool to circumvent access controls or platform rules. Keep your Browserless crawl clean and defensible:
- Respect each site's terms and its
robots.txt; collect only public data you're permitted to use. - Throttle with realistic delays between navigations so you don't overload servers — remote headless browsers are heavier than a plain HTTP client.
- Collect only what you need, and handle any personal data in line with the GDPR. See is web scraping legal in the EU.
- Be honest about who you are — don't impersonate a service or misuse a target's security mechanisms.
Whether mobile proxies themselves are lawful to use: are mobile proxies legal.
FAQ
How do I use a custom proxy with Browserless?
Add externalProxyServer to the connect URL with your endpoint URL-encoded, for example ...?token=TOKEN&externalProxyServer=http%3A%2F%2FUSER%3APASS%40PROXY_HOST%3APORT. Both Puppeteer and Playwright then route every request through that German mobile IP — credentials go inline in the encoded URL.
Does Browserless bill my own proxy as proxy units?
No. Third-party proxy traffic routed via externalProxyServer is not billed as Browserless proxy units — only Browserless's own built-in proxies consume them. You still need a paid plan; free tiers return 401 when an external proxy is set.
Can I combine my German mobile proxy with a Browserless built-in proxy?
No. Setting externalProxyServer together with a built-in option like proxy=residential returns a 400 error. Pick one — for a dedicated German mobile IP, use externalProxyServer alone and point it at your endpoint.
Does the external proxy work with both Puppeteer and Playwright?
Yes. The externalProxyServer parameter lives on the connect URL, so it is library-agnostic. Use it with puppeteer.connect({ browserWSEndpoint }) or chromium.connect(endpoint) — the same German mobile endpoint, the same query parameter. Compare the local Puppeteer setup if you run the browser yourself.
Do I need to URL-encode the proxy in the connect string?
Yes. The endpoint URL sits inside another URL as a query value, so encode it with encodeURIComponent so the ://, @ and : characters don't break parsing. Credentials embedded as USER:PASS@ must be encoded too.
Should I check for WebRTC and DNS leaks with Browserless?
Yes. The proxy routes the browser's HTTP traffic, but WebRTC can expose a real IP and DNS can resolve outside the tunnel. Verify both before you rely on the setup — see what a WebRTC leak is and what a DNS leak is.
Related guides
- Playwright Proxy Setup: Route via German Mobile IPs
- Puppeteer Proxy Setup: Route via German Mobile IPs
- Hyperbrowser Proxy Setup: Sessions on German Mobile IPs
CTA
Route Browserless sessions over real German mobile IPs. Get your German mobile endpoint — HTTP/SOCKS5/OpenVPN, sticky sessions, on-demand rotation, fair-use 20 GB/day, from a transparent EU provider. Browse the plans to get started.
Get a German mobile proxy: Real 4G/5G IPs from Germany, fair-use 20 GB/day — see German 4G/5G mobile proxy options or start with a dedicated 5G proxy.