🎯 A customizable, anti-detection cloud browser powered by self-developed Chromium designed for web crawlers and AI Agents.👉Try Now
Back to Blog

Playwright + Scrapeless Scraping Browser: Cloud Chromium Over CDP

Ava Wilson
Ava Wilson

Expert in Web Scraping Technologies

05-Aug-2026

Playwright drives a browser; the Scrapeless Scraping Browser gives it one that already lives in the cloud, speaks the Chrome DevTools Protocol, and carries residential egress. Your connect_over_cdp call reaches a real Chromium session over wss://browser.scrapeless.com/api/v2/browser instead of a Chrome you have to install, patch, and keep from standing out.

That single swap — local launch becomes a remote connection — is the whole integration. The Playwright script you already know stays the same. What changes is where the browser runs and which IP it exits from. This guide connects Python Playwright to the Scrapeless Scraping Browser, renders a JavaScript page, reads structured data out of it, and pins the request to a specific country, with every code path executed against the live endpoint.

Why the Scrapeless Scraping Browser for Playwright

The Scraping Browser is a cloud Chromium session you reach over CDP, so Playwright treats it exactly like a browser it launched itself. There is no local Chrome to download, no headless flag to disguise, and no browser process competing for memory on your machine. You connect, you get a Browser object, and the full Playwright API works against it.

Three properties matter for scraping. The session renders JavaScript server-side, so a page built entirely by client scripts arrives with its DOM already populated. The connection carries residential egress that you can pin to a country, so a page that geo-gates its content sees traffic from the region you asked for. And because the browser is remote, the machine running your script never needs a GPU, a display, or a patched Chromium build — the local half is just a websocket client speaking the Chrome DevTools Protocol.

Prerequisites

You need Python 3.9 or newer, the playwright package, and a Scrapeless API key. Get the key on the free plan at app.scrapeless.com; the dashboard shows it on the API-key page. The key travels in the connection URL as the token query parameter, so keep it in an environment variable rather than a literal in your source.

You do not need a local browser binary. connect_over_cdp opens a websocket to a browser that already exists in the cloud, so the usual playwright install chromium step is optional here — the rendering happens on Scrapeless's side of the connection.

Install

Install the Playwright client into your project:

bash Copy
pip install playwright

Put your key in the environment so it never appears in code or logs:

bash Copy
export SCRAPELESS_API_KEY="your_scrapeless_api_key"

Connect Playwright to the cloud browser

Build the websocket URL, then hand it to connect_over_cdp. The endpoint is wss://browser.scrapeless.com/api/v2/browser, and it reads three query parameters: token for your key, sessionTTL for how long the browser stays alive in seconds, and proxyCountry for the egress region. The websocket transport itself follows the WebSocket protocol, and Playwright's browser-type connection API speaks CDP over it:

python Copy
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

API_KEY = os.environ["SCRAPELESS_API_KEY"]

def scraping_browser_url(proxy_country="US", session_ttl=180):
    params = urlencode({
        "token": API_KEY,
        "sessionTTL": session_ttl,
        "proxyCountry": proxy_country,
    })
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

sessionTTL bounds how long a single browser lives; a short value is fine for one page, a longer one keeps the browser warm across a multi-step flow. proxyCountry takes a two-letter code. Everything else is ordinary Playwright.

Render a JavaScript page and extract

Point the connected browser at a page that builds its content in the client, and the rendered DOM is already there when navigation settles. The demo page below ships an empty container and fills it with JavaScript; a plain HTTP fetch returns zero rows, while the cloud browser returns all ten because it ran the scripts first — the DOM you query is the one the HTML parsing and scripting model produced after execution.

python Copy
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

API_KEY = os.environ["SCRAPELESS_API_KEY"]

def scraping_browser_url(proxy_country="US", session_ttl=180):
    params = urlencode({"token": API_KEY, "sessionTTL": session_ttl, "proxyCountry": proxy_country})
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(scraping_browser_url())
    page = browser.new_page()
    page.goto("https://quotes.toscrape.com/js/", wait_until="networkidle")
    quotes = page.query_selector_all(".quote")
    print("quote blocks on JS-rendered page:", len(quotes))
    print("first author:", quotes[0].query_selector(".author").inner_text())
    browser.close()

Running it prints the count and the first record:

text Copy
quote blocks on JS-rendered page: 10
first author: Albert Einstein

The wait_until="networkidle" choice suits a page whose content arrives through a burst of script-driven requests. On an analytics-heavy page that never goes quiet, switch to domcontentloaded plus an explicit wait for the selector you care about, so the run does not hang waiting for a network that never idles.

Get your API key on the free plan: app.scrapeless.com

Pin egress to a country

Change one parameter and the request leaves from a different country. The proxyCountry code selects the residential egress region, which decides both the IP a site sees and, for geo-gated pages, the content it serves. Reading an IP-echo endpoint from two regions shows the exit address changing while the script never moves:

python Copy
import os, json
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

API_KEY = os.environ["SCRAPELESS_API_KEY"]

def scraping_browser_url(country):
    return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
        {"token": API_KEY, "sessionTTL": 180, "proxyCountry": country})

with sync_playwright() as p:
    for country in ("US", "GB"):
        browser = p.chromium.connect_over_cdp(scraping_browser_url(country))
        page = browser.new_page()
        page.goto("https://api.ipify.org?format=json", wait_until="domcontentloaded")
        ip = json.loads(page.inner_text("pre, body"))["ip"]
        print(f"proxyCountry={country} -> cloud egress IP {ip}")
        browser.close()

The two connections exit from two different addresses, neither of which is your machine's:

text Copy
proxyCountry=US -> cloud egress IP 24.93.178.230
proxyCountry=GB -> cloud egress IP 109.149.20.197

That is the practical difference from a local Playwright run: the browser and its exit IP both sit on Scrapeless's side, so rate limits and geo rules attach to the pinned region rather than to your workstation.

Working with the session

Everything past the connection is standard Playwright, because the object you hold is a normal Browser. page.screenshot() captures what the cloud Chromium rendered, page.click() and page.fill() drive forms, and page.evaluate() runs JavaScript in the page context. A single connection can open several pages, and closing the browser ends the remote session; if you set a long sessionTTL and disconnect without closing, the session expires on its own when the time runs out.

Keep your automation inside a site's stated boundaries. Read the target's terms and its the Robots Exclusion Protocol file, request only public pages, and keep concurrency modest. Rendering a page in the cloud does not change what a site permits you to collect. For a broader walk through discovery and extraction patterns, the guide on building a web scraper from scratch pairs well with this one.

Conclusion

Connecting Playwright to the Scrapeless Scraping Browser keeps your script and swaps the runtime. You still write goto, query_selector_all, and screenshot; the browser executing them is a cloud Chromium session with residential egress you can pin by country, reached over a single CDP websocket. The two runs above — ten quotes from a JavaScript page, two exit IPs from two regions — are the whole contract: render server-side, extract normally, control where the traffic leaves from. Read the current capabilities on the Scraping Browser product page and check session and egress limits against your volume on the pricing page.

Join our community to claim a free plan and compare notes with other developers building browser automation: Discord · Telegram.

FAQ

Q: Do I need to install Chrome or run playwright install to use the Scraping Browser?

No. The browser runs in Scrapeless's cloud, so connect_over_cdp only needs the playwright client package. A local browser download matters only if you also launch browsers on your own machine.

Q: Which Playwright bindings can connect to it?

Any Playwright binding that exposes a connect-over-CDP method works, because the endpoint speaks the Chrome DevTools Protocol. The examples here use Python's sync_playwright, and the same URL fits the async API and the Node binding.

Q: How do I make the request come from a specific country?

Set the proxyCountry query parameter on the connection URL to a two-letter country code. The connection then exits from residential egress in that region, which is what a geo-gated page keys its content on.

Q: How is this different from running Playwright locally?

A local run launches Chrome on your machine and exits from your IP. The Scraping Browser runs Chromium in the cloud with residential egress, so you skip the local browser entirely and control the exit region through a query parameter.

Q: How long does a browser session stay open?

The sessionTTL parameter sets the lifetime in seconds. Closing the browser ends the session immediately; if you disconnect without closing, the session ends on its own when the TTL elapses.

Q: Can I take screenshots and fill forms, or only read the DOM?

The full Playwright API is available. Because the connected object is an ordinary Browser, page.screenshot(), page.click(), page.fill(), and page.evaluate() all behave as they do locally.

Q: Which wait strategy should I use for JavaScript pages?

Use networkidle for pages whose content arrives in a short burst of requests, and domcontentloaded plus an explicit wait for a known selector on pages that keep a background connection open. The second pattern avoids waiting on a network that never goes quiet.

At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.

Most Popular Articles

Catalogue