Browser Automation with Playwright and Proxies
Browser automation creates a much louder fingerprint than plain HTTP requests because the target sees full page loads, scripts, cookies, and multi-step navigation. Proxy choice matters most when the browser must log in, keep state, or repeat actions without looking like one obvious datacenter bot.
Guardrail: keep the browser proxy server set to the exact endpoint shown in your portal. Add stickiness or provider selection in the username field instead of inventing alternate hosts or ports.What browser automation needs from a proxy
- Sticky identity across login, navigation, form submission, and follow-up page loads.
- Residential traffic when the target is sensitive to automation and datacenter routing.
- Predictable proxy auth that works in the browser launch configuration.
- Deliberate session turnover so one long automation run does not poison future runs.
Which NinjaProxy product fits and why
| Proxy setup | Best for | Why |
|---|---|---|
| Sticky residential session | Playwright login flows, carts, and multi-step account actions | One stable residential route reduces breakage when the site expects the same client through the whole flow. |
| Rotating residential | Short-lived browser runs that should look unrelated | Fresh residential routes are a better fit when each run is independent and should not share identity. |
| ISP/static | Long-lived browser jobs that need one stable IP over time | Static identity is useful when a partner system or allowlist expects a consistent origin. |
Working code example
This Playwright example keeps the gateway endpoint fixed and places stickiness in the proxy username. That matches the currently documented authentication flow for rotating gateways.
import { chromium } from "playwright"
const browser = await chromium.launch({
proxy: {
server: "http://<ROTATING_HTTP_ENDPOINT>",
username: "<USERNAME>--session-browser-run-01--duration-300--provider-res",
password: "<API_KEY>",
},
})
const page = await browser.newPage()
await page.goto("https://example.com/login", { waitUntil: "networkidle" })
await page.fill('input[name="email"]', "[email protected]")
await page.fill('input[name="password"]', "super-secret")
await page.click('button[type="submit"]')
await page.waitForLoadState("networkidle")
console.log(await page.title())
await browser.close()Common failure modes
| Failure | Likely cause | Fix |
|---|---|---|
| Login breaks between steps | The browser changed routes mid-flow. | Use a sticky session token and a duration long enough to cover the full run. |
| Automation gets challenged immediately | Datacenter traffic is too easy for the target to flag. | Move the workflow to residential traffic and reduce run parallelism. |
| Proxy auth fails in Playwright | The endpoint, username, or password fields are malformed. | Use the exact portal endpoint in server and keep controls only in username. |
| Every run reuses the same IP unexpectedly | The same session token is being reused across jobs. | Generate a fresh session token per job when you want route rotation between runs. |
Related docs
- Node.js integration for the current Playwright proxy launch pattern.
- Python integration for the Python Playwright variant.
- Authentication for username + API key and structured rotating username controls.
- Rotating proxies for sticky sessions and provider selection.
- Troubleshooting for auth, timeout, and route-behavior failures.
