Integration

Use Shifter with Playwright

Run Chromium, Firefox, and WebKit through Shifter's residential and ISP proxies — credentials inline, no sidecar extension required. First-class proxy support across Node, Python, Java, and .NET.

Quick Start

Install

npm install playwright

Basic Usage

import { chromium } from "playwright";

const browser = await chromium.launch({
  proxy: {
    server: "http://p.shifter.io:443",
    username: "customer-USERNAME-country-us-sid-123ABC",
    password: "PASSWORD",
  },
});

const page = await browser.newPage();
await page.goto("https://ipinfo.io/json");
console.log(await page.textContent("body"));
// {"ip": "154.16.xxx.xxx", "city": "New York", "country": "US", ...}

await browser.close();

Features

Native proxy support with credentials inline — no sidecar extension or browser tweaking required
Same setup works for Chromium, Firefox, and WebKit on every supported platform
Per-context proxy configuration lets you mix countries inside one browser instance
Identical API across Node, Python, Java, and .NET — same proxy dict in every language
Geo-targeting in 195+ countries via username parameters — country, region, city, ASN
Per-request rotation by default, with `sid` for sticky sessions and `ttl-N` for timed pins of N seconds

Examples

Per-Context Geo-Targeting (one browser, many regions)

Each browser context can have its own proxy. Spin up a US context, a UK context, and a JP context inside one browser instance — Playwright's killer feature for parallel localized scraping.

import { chromium } from "playwright";

const browser = await chromium.launch();

async function makeContext(country: string, sid: string) {
  return browser.newContext({
    proxy: {
      server: "http://p.shifter.io:443",
      username: `customer-USERNAME-country-${country}-sid-${sid}`,
      password: "PASSWORD",
    },
    userAgent:
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
  });
}

const [us, uk, jp] = await Promise.all([
  makeContext("us", "us-001"),
  makeContext("uk", "uk-001"),
  makeContext("jp", "jp-001"),
]);

const [usPage, ukPage, jpPage] = await Promise.all([
  us.newPage(),
  uk.newPage(),
  jp.newPage(),
]);

await Promise.all([
  usPage.goto("https://www.example.com"),
  ukPage.goto("https://www.example.co.uk"),
  jpPage.goto("https://www.example.jp"),
]);

console.log({
  us: await usPage.title(),
  uk: await ukPage.title(),
  jp: await jpPage.title(),
});

await browser.close();

Multi-Browser (Chromium / Firefox / WebKit)

Same proxy config across all three engines. Useful for cross-browser scraping or for picking the engine least likely to trigger bot detection on a given target.

import { chromium, firefox, webkit, type BrowserType } from "playwright";

const proxy = {
  server: "http://p.shifter.io:443",
  username: "customer-USERNAME-country-de-city-berlin-sid-456DEF",
  password: "PASSWORD",
};

async function visit(engine: BrowserType, label: string) {
  const browser = await engine.launch({ proxy });
  const page = await browser.newPage();
  await page.goto("https://example.de");
  const title = await page.title();
  await browser.close();
  return { label, title };
}

const results = await Promise.all([
  visit(chromium, "chromium"),
  visit(firefox, "firefox"),
  visit(webkit, "webkit"),
]);

console.log(results);

Playwright Test Suite

Configure Shifter once in playwright.config.ts so every test routes through the proxy. Use environment variables for credentials so you don't commit them to source.

// playwright.config.ts
import { defineConfig } from "@playwright/test";

export default defineConfig({
  testDir: "./tests",
  workers: 4,

  use: {
    proxy: {
      server: "http://p.shifter.io:443",
      username: process.env.SHIFTER_USER!, // e.g. customer-USERNAME-country-us-sid-test
      password: process.env.SHIFTER_PASS!,
    },
    userAgent:
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    viewport: { width: 1920, height: 1080 },
    ignoreHTTPSErrors: false,
  },
});

// tests/products.spec.ts
import { test, expect } from "@playwright/test";

test("US homepage renders", async ({ page }) => {
  await page.goto("https://example.com");
  await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
});

test("Product page parses", async ({ page }) => {
  await page.goto("https://example.com/products/123");
  const price = await page.locator(".price").textContent();
  expect(price).toMatch(/^\$\d+/);
});

Python: chromium.launch with Sticky Session

Playwright is identical across languages. Same dict-shaped proxy config in Python — and the rest of the API mirrors the Node version.

# pip install playwright
# playwright install chromium

import asyncio
import secrets
from playwright.async_api import async_playwright

async def main():
    sid = secrets.token_hex(4)

    async with async_playwright() as p:
        browser = await p.chromium.launch(
            proxy={
                "server": "http://p.shifter.io:443",
                "username": f"customer-USERNAME-country-fr-city-paris-sid-{sid}-ttl-300",
                "password": "PASSWORD",
            }
        )

        context = await browser.new_context(
            user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
        )

        page = await context.new_page()

        # Multi-step flow — same residential IP across every navigation.
        await page.goto("https://example.fr/login", wait_until="networkidle")
        await page.fill("#email", "user@example.com")
        await page.fill("#password", "secret")
        await page.click("button[type=submit]")
        await page.wait_for_url("**/dashboard")

        rows = await page.locator(".order-row").all_text_contents()
        print(f"Found {len(rows)} orders")

        await browser.close()

asyncio.run(main())
FAQ

Frequently asked questions

Common questions about using Shifter with Playwright.

Pass a `proxy` field on the browser launch options with `server`, `username`, and `password`. Same shape across Chromium, Firefox, and WebKit. Credentials are passed inline — no extension required, and it works in headless mode out of the box.

Yes. Pass `proxy` to `browser.newContext()` and that context will use a different proxy than the rest of the browser. This is the cleanest way to scrape multiple countries in parallel inside one process — way more memory-efficient than launching multiple browsers.

Yes. The same proxy configuration works across all three engines. Firefox and WebKit are useful when a target has Chrome-specific bot detection — Playwright is one of the few tools where switching engines is a one-line change.

Add a session ID to the proxy username — for example `customer-USERNAME-country-us-sid-123ABC`. Every navigation, request, and tab inside that context will reuse the same residential IP. Add `ttl-N` to pin it for up to N seconds.

Yes. Set the `use.proxy` field in `playwright.config.ts`. Every test that doesn't override it inherits the Shifter proxy. Use environment variables for the credentials so they don't end up in source control.

Yes — Playwright has first-party clients for Python, Java, and .NET. The proxy configuration uses the same shape (server, username, password) across every language. The examples on this page show both Node and Python, but the same setup works everywhere.

Get started

Start Using Shifter with Playwright

Drive Chromium, Firefox, and WebKit through Shifter's 205M+ residential and ISP proxies — credentials inline, no extensions required. Works across Node, Python, Java, and .NET.

Try Shifter for FreeSet up in minutes. Cancel anytime.