Nullprint
All tools / Playwright

How to use Playwright with Nullprint

Attach Playwright scripts to any Nullprint profile over CDP, with its fingerprint and proxy intact.

What it is

Playwright is Microsoft's open-source browser automation library. Nullprint starts the profile; Playwright attaches to it over the Chrome DevTools Protocol.

Set it up in Nullprint

  1. Keep the Nullprint app running. Find the port and key in ~/.nullprint/daemon.json (Windows: %USERPROFILE%\.nullprint\daemon.json). The key is also on the Automation page.
  2. Turn on External debugging for the profile: open the profile, expand Expert mode and tick External debugging (it asks for step-up verification). From a script, do the same two things: POST /profiles/{name}/external-debug-grant with an x-np-stepup ticket, then PATCH /profiles/{name} with {"launch": {"externalDebug": true}}. Without both, cdp_endpoint stays null — profiles don't open a debugging port by default.
  3. Install: pip install requests playwright
  4. Launch the profile, wait for its CDP endpoint, attach:
    import json, os, time, requests
    from playwright.sync_api import sync_playwright
    
    cfg = json.load(open(os.path.expanduser("~/.nullprint/daemon.json")))
    BASE = f"http://127.0.0.1:{cfg['port']}"
    H = {"X-API-Key": cfg["api_key"]}
    NAME = "shop-01"  # the internal ID from GET /profiles, not the display label
    
    requests.post(f"{BASE}/profiles/{NAME}/launch", json={"headless": False}, headers=H).raise_for_status()
    while True:  # launch is asynchronous
        p = requests.get(f"{BASE}/profiles/{NAME}", headers=H).json()
        if p.get("status") == "running" and p.get("cdp_endpoint"):
            break
        time.sleep(1)
    
    with sync_playwright() as pw:
        browser = pw.chromium.connect_over_cdp(p["cdp_endpoint"])
        ctx = browser.contexts[0]
        page = ctx.pages[0] if ctx.pages else ctx.new_page()
        page.goto("https://example.com")
        print(page.title())
        browser.close()  # only disconnects
    
    requests.post(f"{BASE}/profiles/{NAME}/stop", headers=H)  # this closes the browser
  5. Node.js: same steps with chromium.connectOverCDP(endpoint).

Full API reference: Local API docs

Why they work well together

FAQ

Does closing Playwright close the browser?

No, it only disconnects. Call POST /profiles/{name}/stop.

Can I set the proxy from code?

Yes: PATCH /profiles/{name} with proxy, or add it to the pool with POST /proxies and assign it.

Headless?

Pass "headless": true to launch.

Visit Playwright ↗Try Nullprint free for 7 days

Also works with