How to Use AdsPower with Playwright for Reliable E2E Testing

Take a Quick Look

Learn how to connect AdsPower anti-detect profiles with Playwright for stable, isolated end-to-end testing of multi-account and geo-sensitive web apps.

How to Use AdsPower with Playwright for Reliable E2E Testing

End-to-end tests fail for reasons that have nothing to do with your code: a shared cookie jar, a fingerprint that changes between runs, or a proxy that rotates mid-session. AdsPower solves the identity problem by giving every test run its own isolated browser profile with a stable fingerprint. Playwright solves the control problem with fast, reliable automation across Chromium, Firefox, and WebKit.

This article explains how the two fit together, how to wire them up, and which testing problems the combination actually removes.

Why pair an anti-detect browser with Playwright?

First viewport screenshot of Fast and reliable end-to-end testing for modern web apps | Playwright

First viewport screenshot of Fast and reliable end-to-end testing for modern web apps | Playwright.

Playwright already isolates browser contexts, so a fair question is why you would add an anti-detect browser at all. The answer is that Playwright's isolation is in-memory and temporary. Close the browser and the context is gone. AdsPower's isolation is persistent and identity-level: each profile keeps its own fingerprint, cookies, local storage, and proxy binding across sessions.

That difference matters when your tests need to:

  • Simulate several distinct users on the same site without cross-contamination
  • Keep a logged-in session alive across multiple test runs
  • Verify behavior from different countries using country-specific IPs
  • Reproduce a bug that only appears under a specific device fingerprint
  • Run automation against accounts that anti-fraud systems would otherwise link together

A proxy in Playwright is configured per browser context, which is useful, but proxy configuration alone does not change Canvas, WebGL, or user-agent signals. AdsPower handles that layer.

How the two tools divide the work

Think of the split like this:

Layer Handled by
Test logic, assertions, selectors, retries Playwright
Browser binary and rendering engine AdsPower (SunBrowser on Chromium, FlowerBrowser on Firefox)
Fingerprint parameters (Canvas, WebGL, network, user agent) AdsPower
Proxy binding per identity AdsPower
Session persistence (cookies, storage) AdsPower profile
Parallel execution and reporting Playwright

Playwright drives the browser. AdsPower decides what the browser looks like to the website.

Prerequisites

Before you start, confirm you have:

  1. AdsPower installed and at least one profile created. The free plan includes 2 profiles, which is enough to prototype the workflow.
  2. Node.js and Playwright installed in your project (npm init playwright@latest).
  3. The AdsPower Local API enabled in the client. You will need the API port and, if configured, the API key.
  4. Proxies assigned to the profiles you plan to test. If you are still choosing a setup, the community comparison of anti-detect browser and proxy pairings is a useful reality check on which combinations stay stable over weeks rather than hours.

Step 1: Start the AdsPower Local API

Open the AdsPower client and go to the API section. Enable the local API service and note the port (the default is typically 50325). If your team requires authentication, generate an API key and store it in an environment variable rather than in source control.

Verify the service responds before writing any test code:

curl http://local.adspower.net:50325/status

A healthy response confirms the client is running and reachable.

Step 2: Start a profile and get its debug endpoint

First viewport screenshot of Release notes | Playwright .NET

First viewport screenshot of Release notes | Playwright .NET.

The AdsPower API exposes an endpoint that launches a profile and returns a WebSocket debugger URL. That URL is what Playwright connects to.

async function startAdsPowerProfile(profileId) {
  const url = `http://local.adspower.net:50325/api/v1/browser/start?user_id=${profileId}`;
  const res = await fetch(url);
  const data = await res.json();

  if (data.code !== 0) {
    throw new Error(`AdsPower start failed: ${data.msg}`);
  }

  return data.data.ws.puppeteer;
}

The returned value is a Chrome DevTools Protocol endpoint. Despite the field name, it works with any CDP-compatible client, including Playwright.

Step 3: Connect Playwright to the running profile

First viewport screenshot of Release notes | Playwright

First viewport screenshot of Release notes | Playwright.

Use chromium.connectOverCDP to attach to the already-running browser rather than launching a new one.

const { chromium } = require('playwright');

async function runTest(profileId) {
  const wsEndpoint = await startAdsPowerProfile(profileId);
  const browser = await chromium.connectOverCDP(wsEndpoint);

  const context = browser.contexts()[0];
  const page = context.pages()[0] || await context.newPage();

  await page.goto('https://example.com/dashboard');
  await page.waitForLoadState('networkidle');

  // Your assertions here
  const title = await page.title();
  console.log('Loaded:', title);

  await browser.close();
}

Two details matter here. First, you are attaching to an existing context, so do not create a new one — the fingerprint and proxy live in the profile AdsPower launched. Second, always close the browser connection when the test finishes, then call the AdsPower stop endpoint so the profile is released for the next run.

Step 4: Stop the profile cleanly

Leaked profiles are the most common cause of flaky multi-account test suites. Add a teardown step:

async function stopAdsPowerProfile(profileId) {
  await fetch(
    `http://local.adspower.net:50325/api/v1/browser/stop?user_id=${profileId}`
  );
}

Wrap this in a finally block or a Playwright fixture so it runs even when a test fails.

Step 5: Run profiles in parallel

Playwright's worker model maps naturally onto AdsPower profiles. Assign one profile per worker, and each worker gets a fully isolated identity.

// playwright.config.js
module.exports = {
  workers: 4,
  use: {
    // Base config; profile assignment happens per test
  },
};

A simple pattern is to keep an array of profile IDs and index into it using the worker index, so no two workers ever touch the same profile at the same time.

Practical example: testing geo-specific pricing

First viewport screenshot of Release notes | Playwright

First viewport screenshot of Release notes | Playwright.

Suppose your application shows different prices based on the visitor's country. You want to verify the German, Japanese, and Brazilian variants.

  1. Create three AdsPower profiles, each bound to a residential proxy in the target country.
  2. Set each profile's language and timezone to match the proxy location.
  3. In your test, start the profile, connect over CDP, navigate to the pricing page, and assert the currency and amount.
const cases = [
  { profileId: 'de_profile', currency: 'EUR' },
  { profileId: 'jp_profile', currency: 'JPY' },
  { profileId: 'br_profile', currency: 'BRL' },
];

for (const testCase of cases) {
  const wsEndpoint = await startAdsPowerProfile(testCase.profileId);
  const browser = await chromium.connectOverCDP(wsEndpoint);
  const page = browser.contexts()[0].pages()[0];

  await page.goto('https://example.com/pricing');
  const shown = await page.locator('[data-testid="currency"]').innerText();

  if (shown !== testCase.currency) {
    throw new Error(`Expected ${testCase.currency}, got ${shown}`);
  }

  await browser.close();
  await stopAdsPowerProfile(testCase.profileId);
}

This is where the combination earns its keep. A plain Playwright run with a single proxy would require you to rebuild context state for every country and would still expose the same fingerprint across all three tests.

Practical example: keeping a logged-in session across runs

Some flows — onboarding, multi-step checkout, account warmup — are expensive to repeat. Because the AdsPower profile persists cookies and storage, you can log in once and reuse the session:

  1. Run a setup script that starts the profile, connects, performs login, and closes the connection without clearing storage.
  2. In subsequent test runs, connect to the same profile and navigate directly to the authenticated area.
  3. Add a guard that detects a logged-out state and re-authenticates, so the suite self-heals.

This pattern is common in multi-account operations, where session longevity is the metric that matters most. If you are managing many accounts rather than many tests, the same principles are covered in this guide to multi-accounting with anti-detect browsers.

Where this combination breaks down

It is worth being honest about the limits.

  • AdsPower is not a test runner. It has no assertions, reporters, or retry logic. Playwright supplies all of that.
  • Fingerprint realism varies by configuration. Third-party comparisons of anti-detect browsers, such as this AdsPower vs Vision breakdown, have raised questions about automatically generated hardware parameters. Test your profiles against a fingerprint checker before trusting them in production-like suites.
  • CDP attachment has overhead. Connecting to an existing browser is slower than launching a fresh headless instance. For pure unit-level UI tests, plain Playwright is faster.
  • Profile count is a real constraint. The free plan's 2 profiles limit parallelism. Scale plans accordingly.

When to use this setup — and when not to

Use AdsPower with Playwright when your tests depend on identity: multi-account flows, geo-targeted content, session persistence, or fingerprint-sensitive rendering. Use plain Playwright when you are testing UI logic that has nothing to do with who the visitor appears to be.

A practical rule: if two test runs would be indistinguishable to the server, you do not need an anti-detect browser. If they must look like two different people on two different machines, you do.

Related reading

FAQ

Can Playwright launch AdsPower profiles directly?

No. AdsPower launches the browser; Playwright attaches to it over the Chrome DevTools Protocol using the WebSocket endpoint returned by the AdsPower Local API.

Does this work with FlowerBrowser (Firefox)?

Playwright's connectOverCDP is Chromium-specific. For Firefox-based profiles, you need a different attachment strategy, and support depends on the debug protocol the profile exposes. SunBrowser (Chromium) is the straightforward path.

How do I avoid profile collisions in parallel runs?

Assign each Playwright worker a unique profile ID and never reuse a profile while it is running. Track profile state in a fixture and release it in teardown.

Can I set the proxy from Playwright instead of AdsPower?

You can, but you should not. The proxy is part of the profile's identity. Setting it in Playwright while AdsPower reports a different network configuration creates an inconsistency that fingerprint checkers will flag.

Is the Local API secure?

It binds to localhost by default. If you enable an API key, store it in environment variables and never commit it. For team setups, restrict access to the machine running the AdsPower client.

What about CAPTCHAs during automated tests?

Automated flows often trigger challenges. Handling them is a separate concern from browser identity; the workflow for integrating a solving service is documented in this AdsPower and Anti Captcha setup guide.

Conclusion

AdsPower and Playwright solve different halves of the same problem. Playwright gives you a fast, expressive way to drive a browser and assert on what it renders. AdsPower gives each of those browser sessions a believable, persistent, isolated identity with its own fingerprint and proxy.

Together they let you test multi-account behavior, geo-specific experiences, and long-lived sessions without the flakiness that comes from shared state. The setup is not complicated — enable the Local API, start a profile, connect over CDP, and clean up in teardown — but the discipline of treating profiles as first-class test fixtures is what separates a stable suite from a fragile one.

Start with two profiles on the free plan, prove the workflow on a single geo test, then scale the pattern to your full matrix.

Share