# CloakBrowser residential proxy integration for useful browser data

[← All guides](https://proxylane.dev/blog) 

INTEGRATION GUIDES · 5 MIN READ

Connect CloakBrowser to a residential proxy, choose session behavior by workload, verify the exit in the same browser, and clean up safely.

**Founder, ProxyLane**Published September 16, 2026

On this page [Install the actual package](https://proxylane.dev/blog/cloakbrowser-proxy#install-the-actual-package)  [Choose residential or datacenter by the job](https://proxylane.dev/blog/cloakbrowser-proxy#choose-residential-or-datacenter-by-the-job)  [Pass credentials through the launch API](https://proxylane.dev/blog/cloakbrowser-proxy#pass-credentials-through-the-launch-api)  [Preserve a session only when pages are related](https://proxylane.dev/blog/cloakbrowser-proxy#preserve-a-session-only-when-pages-are-related)  [Diagnose the failure phase](https://proxylane.dev/blog/cloakbrowser-proxy#diagnose-the-failure-phase)

**Get the data you need**

Power your research, price monitoring or AI agent with useful web data. Spend less time on proxy setup.

 [Get started ↗](https://proxylane.dev/register)

CloakBrowser gives a Python or JavaScript program a Playwright-compatible browser. Its documented `launch()` API takes the proxy, while `launchPersistentContext` provides the JavaScript persistent option. A residential proxy supplies the network exit. To get useful browser data, bind both in the same launch and check the exit and run a target-content smoke check before building record extraction.

 

## Install the actual package

 

Python:

 

```bash
python -m pip install cloakbrowser
```

 

JavaScript requires Node.js 20 or newer:

 

```bash
npm install cloakbrowser playwright-core
```

 

The wrapper downloads its browser binary on first launch. Set `PROXY_SERVER`, `PROXY_USER`, `PROXY_PASSWORD`, `EXIT_CHECK_URL`, `EXPECTED_EXIT_MARKER`, `TARGET_URL` and `EXPECTED_TARGET_MARKER` in the runtime environment. The two marker variables are required by the examples. A username and password are optional only when the purchased endpoint is allowlisted; if either is set, set both.

 

## Choose residential or datacenter by the job

 

Residential is a sensible choice when the permitted workflow depends on a documented residential or access-network signal, or when a region-sensitive page must be checked from the purchased route. Datacenter can be the better fit for open public pages when the target accepts cloud egress and throughput or cost matters more than that network property. Neither label tells you whether the target will return the record you need.

 

| Workload | Start with | Keep stable or change | Acceptance check |
| --- | --- | --- | --- |
| Public pages and independent records | Datacenter, if accepted by the target | One route per independent request | Expected title, status and fields |
| Region-sensitive pages | Residential only when that property is part of the route you bought | Keep the same route through related pages | Same-browser exit and expected locale or record |
| Login, pagination or checkout-like sequence you own | Whichever route the target and provider permit | Sticky session and persistent profile | Exit remains stable and state survives the sequence |
| Independent country or market observations | Route matching each observation | New session or provider-defined rotation between items | Record exit, final URL and field-level result |

 

CloakBrowser does not provide proxy rotation. Rotation belongs to the proxy provider's endpoint or session parameters, and the browser must be relaunched or reconfigured according to that provider's contract. Do not rotate between a login page, pagination request and detail page when those pages share state.

 

## Pass credentials through the launch API

 

The official Python wrapper accepts a proxy URL or a Playwright-style object with `server`, `bypass`, `username` and `password`. The JavaScript types expose the same shape. Build that object from the runtime environment so the password never enters page code, a committed file or a log.

 

```python
import os
from urllib.parse import urlsplit

from cloakbrowser import launch

required = [
    "PROXY_SERVER",
    "EXIT_CHECK_URL",
    "EXPECTED_EXIT_MARKER",
    "TARGET_URL",
    "EXPECTED_TARGET_MARKER",
]
missing = [name for name in required if not os.environ.get(name, "").strip()]
if missing:
    raise RuntimeError("Missing required environment variables: " + ", ".join(missing))
if bool(os.environ.get("PROXY_USER")) != bool(os.environ.get("PROXY_PASSWORD")):
    raise RuntimeError("PROXY_USER and PROXY_PASSWORD must be set together")

proxy = {"server": os.environ["PROXY_SERVER"]}
if os.environ.get("PROXY_USER"):
    proxy["username"] = os.environ["PROXY_USER"]
    proxy["password"] = os.environ["PROXY_PASSWORD"]

browser = launch(proxy=proxy)
try:
    page = browser.new_page()
    route = page.goto(
        os.environ["EXIT_CHECK_URL"],
        wait_until="domcontentloaded",
        timeout=20_000,
    )
    route_body = page.locator("body").inner_text()
    expected_exit = os.environ["EXPECTED_EXIT_MARKER"]
    route_ok = (
        route is not None
        and route.status == 200
        and route_body.strip() == expected_exit.strip()
    )
    if not route_ok:
        raise RuntimeError("The same-browser exit check failed")

    target = page.goto(
        os.environ["TARGET_URL"],
        wait_until="domcontentloaded",
        timeout=20_000,
    )
    target_marker = os.environ["EXPECTED_TARGET_MARKER"]
    target_body = page.locator("body").inner_text()
    data_ok = (
        target is not None
        and target.status == 200
        and target_marker in target_body
    )
    if not data_ok:
        raise RuntimeError("The target response failed validation")

    print({
        "route_status": route.status,
        "route_ok": route_ok,
        "target_status": target.status,
        "target_path": urlsplit(page.url).path,
        "data_ok": data_ok,
    })
finally:
    browser.close()
```

 

Set `EXIT_CHECK_URL` to `https://api.ipify.org`, whose  [official documentation](https://www.ipify.org/)  specifies a plain-text IPv4 response, or a trusted endpoint with that same response format. Set `EXPECTED_EXIT_MARKER` to the complete expected IPv4 address. Both examples compare the entire trimmed response with that value; a partial IP cannot pass. This checks the exit of that browser request. A provider's rotating endpoint may use another exit for the next request, including the target.

 

Set `EXPECTED_TARGET_MARKER` to a distinctive expected record value, such as a product's exact SKU. Generic site text is insufficient. The target check establishes only HTTP 200 and the presence of that substring in the page body. It does not extract or validate record fields; add those assertions before accepting records. Keep any retained exit evidence redacted.

 

For JavaScript, the launch and cleanup boundary is equivalent:

 

```javascript
import { launch } from 'cloakbrowser';

const required = [
  'PROXY_SERVER',
  'EXIT_CHECK_URL',
  'EXPECTED_EXIT_MARKER',
  'TARGET_URL',
  'EXPECTED_TARGET_MARKER',
];
const missing = required.filter((name) => !process.env[name]?.trim());
if (missing.length) {
  throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
if (Boolean(process.env.PROXY_USER) !== Boolean(process.env.PROXY_PASSWORD)) {
  throw new Error('PROXY_USER and PROXY_PASSWORD must be set together');
}

const proxy = { server: process.env.PROXY_SERVER };
if (process.env.PROXY_USER) {
  proxy.username = process.env.PROXY_USER;
  proxy.password = process.env.PROXY_PASSWORD;
}

let browser;
try {
  browser = await launch({ proxy });
  const page = await browser.newPage();
  const exitResponse = await page.goto(process.env.EXIT_CHECK_URL, {
    waitUntil: 'domcontentloaded',
    timeout: 20_000,
  });
  const exitBody = await page.locator('body').innerText();
  const exitOk =
    exitResponse?.status() === 200 &&
    exitBody.trim() === process.env.EXPECTED_EXIT_MARKER.trim();
  if (!exitOk) throw new Error('The same-browser exit check failed');

  const response = await page.goto(process.env.TARGET_URL, {
    waitUntil: 'domcontentloaded',
    timeout: 20_000,
  });
  const targetBody = await page.locator('body').innerText();
  const dataOk =
    response?.status() === 200 &&
    targetBody.includes(process.env.EXPECTED_TARGET_MARKER);
  console.log(JSON.stringify({
    exitStatus: exitResponse?.status() ?? null,
    exitOk,
    targetStatus: response?.status() ?? null,
    targetPath: new URL(page.url()).pathname,
    dataOk,
  }));
  if (!dataOk) throw new Error('The target response failed validation');
} finally {
  if (browser) await browser.close();
}
```

 

CloakBrowser also documents inline credential URLs, but an environment-built object makes accidental disclosure harder. Its optional `geoip` mode can derive timezone and locale from the proxy route, so treat that lookup as part of the route check. Its current source routes SOCKS5 through Chrome's `--proxy-server` path. Credentialed HTTP or HTTPS uses Chrome inline authentication only when the selected binary supports it; older platform binaries can fall back to Playwright's proxy object. Keep the protocol exactly as supplied by the proxy provider. Pass raw `PROXY_USER` and `PROXY_PASSWORD` values in object fields; do not percent-encode them. Percent-encoding applies only when constructing inline credential URLs.

 

## Preserve a session only when pages are related

 

Use a persistent profile when cookies and local storage must survive a restart:

 

```python
from cloakbrowser import launch_persistent_context

context = launch_persistent_context(
    "./browser-profile",
    proxy=proxy,
)
try:
    page = context.pages[0] if context.pages else context.new_page()
    page.goto(os.environ["TARGET_URL"])
finally:
    context.close()
```

 

A persistent profile preserves browser state; it does not prove that the proxy exit is sticky. Run the same-browser exit check twice during a controlled sequence and compare the observed exit. If the provider rotates by request, keep only independent records in that session. For a stable workflow, use the provider's documented sticky-session setting and keep one profile and route through the related pages.

 

## Diagnose the failure phase

 

| Observation | Inspect first | Next action |
| --- | --- | --- |
| Binary or import fails | Wrapper version, platform and cache | Run `python -m cloakbrowser info --json` or `npx cloakbrowser info` |
| 407 or proxy authentication error | Protocol, username, password and URL encoding | Check the provider credential pair and the selected binary's auth path |
| Exit check fails in the browser | Proxy host, port, bypass and actual egress | Repeat the check in a clean browser and compare the route record |
| Exit passes but target data is wrong | Final URL, status, locale and required field | Inspect redirects, cookies and page content separately |
| Exit changes mid-sequence | Provider session or rotation policy | Keep a sticky route for related pages or split the job |
| Browser remains after an exception | Missing close path | Put `browser.close()` or `context.close()` in `finally` and remove only task-owned temporary profiles |

 

The repository README currently identifies wrapper `v0.5.10` and a Pro Stable Chromium `151.0.7922.108.6` build, while Python source exposes a bundled baseline `146.0.7680.177.5` in `CHROMIUM_VERSION`. Platform details include Linux `arm64`, and the first launch can download roughly `200 MB` into the local cache. Use the CLI or `binary_info()` to see what will actually launch. `CLOAKBROWSER_VERSION` or `browserVersion` can pin a Chromium version; `CLOAKBROWSER_BINARY_PATH` can select a local binary. `CLOAKBROWSER_LICENSE_KEY` selects license-backed access, and `CLOAKBROWSER_RELEASE_CHANNEL` can select the Preview channel.

 

The Python and JavaScript wrappers are MIT licensed. The compiled browser binary has a separate license, and its terms call the third-party distribution permission an `OEM/SaaS license` for bundling, embedding or providing browser functionality to customers. The official  [`/free` path](https://cloakbrowser.dev/free/)  and paid plans describe different current access routes, so confirm the entitlement before packaging the binary into a service. The proxy route, browser state and target permission remain separate decisions.

 

For the network classification decision, see the  [residential versus datacenter guide](https://proxylane.dev/blog/residential-vs-datacenter-proxies) . For session policy, read the  [rotation and sticky sessions guide](https://proxylane.dev/blog/proxy-rotation-and-sticky-sessions) . The  [Playwright proxy guide](https://proxylane.dev/blog/playwright-proxy) ,  [browser diagnostics guide](https://proxylane.dev/blog/proxy-ip-and-browser-diagnostics)  and  [407 troubleshooting guide](https://proxylane.dev/blog/proxy-error-407)  cover the next checks when the route does not behave as expected.

 

## Sources and further reading

- [https://github.com/CloakHQ/CloakBrowser/blob/main/README.md](https://github.com/CloakHQ/CloakBrowser/blob/main/README.md)

- [https://github.com/CloakHQ/CloakBrowser/blob/main/cloakbrowser/browser.py](https://github.com/CloakHQ/CloakBrowser/blob/main/cloakbrowser/browser.py)

- [https://github.com/CloakHQ/CloakBrowser/blob/main/js/README.md](https://github.com/CloakHQ/CloakBrowser/blob/main/js/README.md)

- [https://github.com/CloakHQ/CloakBrowser/blob/main/js/src/proxy.ts](https://github.com/CloakHQ/CloakBrowser/blob/main/js/src/proxy.ts)

- [https://github.com/CloakHQ/CloakBrowser/blob/main/js/src/playwright.ts](https://github.com/CloakHQ/CloakBrowser/blob/main/js/src/playwright.ts)

- [https://github.com/CloakHQ/CloakBrowser/blob/main/BINARY-LICENSE.md](https://github.com/CloakHQ/CloakBrowser/blob/main/BINARY-LICENSE.md)

- [https://cloakbrowser.dev/](https://cloakbrowser.dev/)

[Sign in ↗](https://proxylane.dev/login)

## Keep reading

[Use cases · 3 min read

### Amazon Scraper API vs Proxy: Choose a Product Data Source

Distinguish authorized Amazon APIs, licensed product data and proxy-based page checks by record quality and access rights.

 Read guide →](https://proxylane.dev/blog/amazon-scraper-api-vs-proxy)   [Integrations · 5 min read

### Apify Custom Proxy Setup: Use Your Own Residential Route

Connect a buyer-owned proxy to an Apify Actor, keep the session boundary clear, and validate records instead of counting requests.

 Read guide →](https://proxylane.dev/blog/apify-custom-proxy)   [Proxy fundamentals · 6 min read

### Australia Residential Proxies: Verify the AU Exit and State-Level Result

Separate Australian egress from en-AU content, AUD pricing, GST display, postcode validation and the state delivery context.

 Read guide →](https://proxylane.dev/blog/australia-residential-proxies)

Canonical source: https://proxylane.dev/blog/cloakbrowser-proxy

Documentation index: https://proxylane.dev/llms.txt
