webscrape.dev

Automating Antidetect Browsers: Local APIs, Playwright Bindings and Profile Ops

Driving antidetect profiles from code: local control APIs, CDP endpoints, Playwright and Puppeteer attachment, and managing profiles as infrastructure.

Nathan Kessler
Nathan Kessler··Reviewed
14 min read

Each tool referenced is evaluated against our methodology using public docs, vendor demos, and hands-on testing.

Every one of the seven major antidetect browsers binds an HTTP server to localhost and will start a profile for you over it. Kameleo listens on 5050, AdsPower on 50325, Octo Browser on 58888. Almost none of the review coverage for antidetect browsers mentions this, because automation gets a checkmark in a comparison row next to the fingerprint matrix and the pricing table. So teams click through a GUI to launch forty profiles one at a time, work a twenty-line script does better.

This guide covers the engineering side of the category: how the local control API pattern works, what the start call returns on each vendor, how to attach Playwright or Puppeteer to the result, and the operational layer nobody writes about. Profiles are state, so they need versioning and a backup path. Concurrency turns out to be a purchasing decision. And a proxy has to be bound to one profile for any of it to hold together.

Scope note: this is about data collection and testing. Running sessions on sites you are authorized to access, verifying how your own product renders across device profiles, collecting public pages that block generic headless traffic. The account-farming use case that dominates this category's marketing is not what this page is for.

The local control API pattern

Every one of these products is the same architecture with different naming. A desktop application or daemon runs on your machine. It holds a library of profiles, each of which is a fingerprint definition plus a browser data directory. It binds an HTTP server to localhost. You POST or GET a start request naming a profile, the daemon launches its patched Chromium or Firefox build with remote debugging enabled, and the response contains the address of that debugging interface.

From that point you are talking to an ordinary CDP endpoint. Playwright and Puppeteer do not know or care that the browser on the other end has a spoofed canvas hash.

The three steps, in every SDK and every language:

# 1. start the profile through the vendor's local API
resp = requests.post(f"{LOCAL_API}/start", json={"profile_id": PROFILE_ID})
ws = resp.json()["ws"]

# 2. attach
browser = playwright.chromium.connect_over_cdp(ws)

# 3. take the EXISTING context, do not create a new one
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()

Step three is where most first attempts go wrong. browser.new_context() creates a fresh incognito-equivalent context with no cookies, no local storage and none of the profile's accumulated state. You will have started an antidetect profile and then thrown away the half of it that mattered. Always take contexts[0].

There is a second and less obvious property of attaching rather than launching. Playwright sets navigator.webdriver and passes --enable-automation when it starts a browser itself. connectOverCDP attaches to a process Playwright did not start, so neither is applied. That is a mechanical difference you can verify yourself in about a minute, and it is part of why this pattern survives checks that a stock headless Playwright run fails.

The cleanup half matters as much. Wrap the work in try/finally and call both browser.close() and the vendor's stop endpoint. An orphaned profile process holds a licence slot, keeps a proxy session open, and on some vendors leaves the profile flagged as running so the next start call fails. Long batch jobs that skip this drift into a state where half the licence is consumed by zombies.

What each vendor returns

The shape is constant. The details are not. The AdsPower row, and the plan figures for Kameleo and Multilogin further down, were read from those vendors' own documentation and pricing pages on 27 July 2026. The Octo Browser, GoLogin, Dolphin Anty and Incogniton rows come from each vendor's published developer documentation but were not re-checked on that date. Ports and paths change: read them from the current docs and your local config rather than from this table.

ToolLocal API surfaceWhat start returnsNotable constraint
KameleoREST on port 5050, plus first-party Python, JavaScript and C# SDKsws://localhost:5050/playwright/{profileId} for Playwright; separate paths for Puppeteer and SeleniumTwo engines. Chroma attaches over CDP; the Firefox-based Junglefox goes through a pw-bridge shim instead
MultiloginLauncher API on port 35000GET /api/v1/profile/start?automation=playwright&profileId=… returns a port; build http://127.0.0.1:{port}automation must be set to selenium, puppeteer or playwright or no port is returned at all
AdsPowerREST on port 50325 by defaultPOST /api/v2/browser-profile/start returns data.ws.puppeteer, data.ws.selenium, data.debug_port and a data.webdriver path to a matching chromedriverDocumented as a paid-account feature; request rate is tied to stored profile count, 2/sec under 200 profiles, 5/sec to 5,000, 10/sec above
Octo BrowserLocal client API on port 58888Pass "debug_port": true and the response carries ws_endpointOne-time profiles are created, launched and auto-deleted in a single call, which suits stateless collection
GoLoginLocal API plus a cloud REST API and SDKsSDK start() / launch() returns a browserWSEndpoint for Puppeteerexit() stops the browser and uploads profile state to GoLogin storage, so state leaves your machine by default
Dolphin AntyDesktop app API on port 3001Automation launch returns a remote debugging port, with a headless flagThird-party reviews from mid-2026 place the Local API on paid plans only; confirm against the current plan page
IncognitonLocal API fronted by Python and Node SDKsSDK startPlaywright(); REST /automation/launch/puppeteer/{profile_id}The browser-automation module is documented as SDK-exclusive, not reachable through raw REST

Two things to take from that table before anything else.

Do not hardcode the port. AdsPower's API overview, read on 27 July 2026, gives http://local.adspower.net:50325/ as the default address and then tells you to read a local_api file for the authoritative one: under AppData\Local\Adspower on Windows, ~/Library/Application Support/Adspower/local_api on macOS, ~/.config/adspower_global/cwd_global/source/local_api on Linux. Read the port from that file or from your own config at startup. A hardcoded port is the failure that surfaces six months later on one machine in the fleet.

Do not assume Firefox behaves like Chromium. Kameleo is the only vendor here shipping a Firefox-based engine alongside its Chromium one, and Junglefox needs Playwright's bridge rather than a CDP connection. If your target detection meaningfully differs between engines, that is a reason to pick Kameleo. If it does not, it is a second code path you did not need.

Profile creation and fingerprint assignment

The launch call is nearly identical everywhere. Profile creation is where the products actually diverge, and it is the part that determines whether your fleet is reproducible.

Kameleo's model is the most explicit about it. You call searchFingerprints with a device type, browser and OS, get back a list of real fingerprint records, and pass one of their ids into createProfile. The fingerprint is a first-class object you selected, so you can record which one a profile got and recreate it. Kameleo's pricing documentation also notes that SearchFingerprints, CreateProfile and StartProfile all count against your per-minute request budget, which is worth knowing before you write a loop that creates two hundred profiles at once.

GoLogin, AdsPower, Multilogin, Octo Browser and Dolphin Anty all expose profile creation through REST as well, with fingerprint parameters supplied as fields on the create call and unspecified values filled in by the vendor's generator. That is more convenient and less reproducible. If the generator picks your WebGL vendor string and you never record what it picked, a profile you delete is gone rather than rebuildable.

The practical rule: whatever the vendor's create call returns, persist the full profile object in your own store immediately. Not the id. The whole thing.

Incogniton is the odd one here for a different reason. Its browser-automation surface is documented as SDK-exclusive, which is fine if you write Python or Node and awkward if your orchestration lives in Go or Rust and speaks HTTP to everything else. It is wrong for a polyglot platform team for that reason alone, regardless of how the browser itself performs.

Treat profiles as infrastructure, not artefacts

The default workflow in this category is manual. Someone opens the desktop app, clicks new profile, picks a fingerprint from a dropdown, pastes in a proxy, names it something, and the organization now owns an artefact nobody can rebuild. Forty of those and you have a fleet with no source of truth.

The alternative is to split a profile into two things that get managed differently.

The definition is deterministic and belongs in version control. Fingerprint selection or explicit parameters, the proxy binding, engine choice, start flags, headless or not, and whatever tags your vendor supports. Store it as JSON or YAML in the same repo as your scrapers. A reconciler script reads the directory, queries the vendor's list endpoint, creates what is missing and updates what has drifted. The desktop GUI becomes a read-only inspection tool.

The state is cookies, local storage, IndexedDB, service worker caches and the profile's browsing history. This cannot be versioned meaningfully and cannot be regenerated. A session cookie that has survived three weeks of normal use carries trust that a fresh login does not, and no amount of configuration recreates it.

Once you have that split, a profile change becomes reviewable in a pull request and a bad fingerprint edit becomes a revert. Onboarding a new machine turns into a reconcile run instead of an afternoon of clicking. You can also answer the question that always comes up after an incident, which is what changed about this profile and when.

This is also the point where naming matters more than it seems. Encode the purpose, the target and the proxy region into the profile name, because the vendor's API returns names in list responses and you will be filtering on them constantly.

Binding a proxy per profile

A fingerprint that stays constant while the exit IP changes every session is a worse signal than no fingerprint spoofing at all. Real users do not move continents between page loads. This is the single most common way a well-configured antidetect fleet gets itself flagged, and it comes from treating the proxy layer as a shared pool rather than a per-profile attribute.

Every vendor in the table supports per-profile proxy configuration, either on the create call or as a separate proxy endpoint. GoLogin additionally resells its own IPs through an addGologinProxyToProfile helper that takes a country code, which is convenient and locks that binding to their pool. Most teams bring their own from a proxy network instead.

The rules that hold across vendors:

  • One profile, one sticky exit IP, for the life of the profile. [Sticky residential proxy sessions](/glossary/sticky-session) or mobile IPs, not a rotating proxy endpoint. Rotation belongs in front of stateless request-level scraping, not behind a persistent identity.
  • Match the IP's geography to the profile's timezone, locale and language headers. A profile claiming Europe/Berlin behind a São Paulo IP fails a check that costs the detector nothing to run.
  • Store the binding in your profile definition, not only in the vendor's database. When you migrate vendors, and this category does see teams migrate, the fingerprint is replaceable and the IP mapping is not.
  • Treat an unrecoverable proxy change as a profile retirement rather than an edit. If the IP is gone, the identity built on it is compromised anyway.

Choosing which proxy type sits behind a given profile is a separate decision with its own tradeoffs, covered in the proxy type by target guide, and the sourcing question behind residential pools is worth understanding before you sign anything: see residential proxy IP sourcing. If a single vendor's pool is load-bearing for your whole fleet, the multi-proxy-vendor failover guide covers what to build before the outage rather than during it.

Cookies and storage between runs

Persistence is the reason to use this category at all. If you did not need state to survive between runs, plain Playwright with a stealth plugin and a browser infrastructure provider would be cheaper and simpler.

Three failure modes account for most lost state.

The first is new_context(), covered above. It silently gives you a clean browser and the run looks like it worked.

The second is where the state physically lives. GoLogin's SDK, by its own documentation, uploads the profile to GoLogin storage when exit() is called. That is a feature if you run the same profile from several machines and a problem if your policy says session material stays on infrastructure you control. Kameleo and Dolphin Anty both document local-only profile storage as an option. Know which mode you are in before you audit it, not after.

The third is process termination. Chromium flushes cookies and IndexedDB on a clean shutdown. Kill the container and recent state is gone. Every batch runner needs a signal handler that calls the vendor's stop endpoint and waits for it, and job timeouts that are generous enough for that shutdown to finish.

One more thing worth doing: verify persistence explicitly rather than assuming it. A ten-line canary that starts a profile, sets a marker in local storage, stops it, restarts it and asserts the marker is still there will catch a broken configuration in seconds. Run it in CI against a throwaway profile.

Concurrency is a licence line, not a hardware line

Teams size these deployments by RAM and then discover the ceiling is contractual.

Kameleo is the clearest case because it prices the constraint directly. Its pricing page, read on 27 July 2026, sells a Concurrent Browsers Limit as the primary unit: 2 on the free tier, 10 on Startup at €59 per month, 100 on Business at €299 and 1,000 on Enterprise at €1,499, with add-on blocks above each. Its documentation states that every running session counts toward the limit whether a human opened it or a script did, and that stored profile counts are separate. Kameleo also documents Docker support as included at every tier with the same limits, which is unusual in a category where headless server operation is often gated.

Everyone else constrains you indirectly, through stored profile counts, seats and request rates. Multilogin's pricing page, read on 27 July 2026, sells plans by profile count in USD: a free tier at 5 profiles, Pro 10 through Pro 100 at $85 to $320 per year on annual billing, and Business from $685 per year at 300 profiles up to $3,600 at 10,000. The same page puts API access on Pro 10 and above, excludes the free tier from it, and documents rate limits of 100 requests per minute on Pro with custom limits on Business. So on Multilogin your automation ceiling is a request rate attached to a profile-count plan, which is a different thing to forecast than a concurrent-session count. AdsPower likewise ties request rate to stored profile count rather than to a plan name. Octo Browser's documentation notes that rate limits are shared across the whole team and vary by subscription level, which means one badly written script can rate-limit every colleague at once.

Prices in this category move constantly. Treat all of the above as a snapshot of published list prices on the date given and check the vendor's own page before you commit.

Then there is the hardware floor, which is real but usually not what binds first. Each running profile is a full browser process. Budget roughly 300MB to 700MB of RAM per instance depending on the pages you load, plus a CPU core for every three or four active profiles if the targets are JavaScript-heavy. Headless mode reduces that cost, and on Kameleo it is not a gating point: the same plan matrix lists headless browser support and Docker on every tier, including free. Its entry-tier restriction is elsewhere, on emulated mobile profiles, which Free and Startup limit to one at a time.

So the planning question is which of the three ceilings you hit first, and whether raising it means a purchase order or another server.

Which one is wrong for you

Recommending all seven would be useless, so here is what each one disqualifies itself from.

Kameleo is the strongest fit for engineering teams doing collection at scale: three first-class SDKs, an explicit fingerprint-search model, Docker and headless on every tier including free, and concurrency priced as a line item you can forecast. It is wrong for a solo operator or a small budget, because concurrency is exactly where it charges. Two concurrent browsers on the free tier is a validation allowance, not a working configuration, and the next step up is €59 per month for 10.

AdsPower has the most convenient start call in the table. The v2 endpoint hands back a Puppeteer WebSocket, a Selenium debug address and the path to a matching chromedriver in one response, so Puppeteer, Playwright and Selenium code paths all attach from the same call without a second lookup. It is wrong for anyone hoping to evaluate automation for free, since its Local API overview grants API permission to paid accounts. It is also wrong for chatty orchestration over a large profile library, because request rate is tied to stored profile count and the bottom band is 2 per second.

Multilogin has mature, actively maintained automation documentation with per-framework examples, and its launcher API is straightforward. It is wrong for evaluating automation at zero cost, since its pricing page excludes the free tier from API access and starts it at Pro 10. It is also organized around profile counts rather than concurrent automated sessions, so a script fleet is harder to forecast than on Kameleo: you are reasoning about 100 requests per minute against a plan sized in stored profiles.

Octo Browser has the single most useful primitive in this category for collection work: one-time profiles that are created, launched and deleted in one API call. If your work is stateless page fetching rather than long-lived identities, that removes the profile-lifecycle problem entirely. It is wrong for anyone on a subscription level below the one that enables the API, so confirm that on Octo Browser's current plan page rather than on this one, and its team-shared rate limits make it awkward for large mixed teams where one script's retry loop becomes everyone's problem.

GoLogin has the widest set of community examples and an MIT-licensed SDK, which shortens the first day considerably. It is wrong for teams under a data-residency constraint, because the default lifecycle uploads profile state to GoLogin's storage on exit.

Dolphin Anty has a well-established local API on port 3001 and long-standing Python community wrappers. It is wrong as a free-tier evaluation for automation specifically, since multiple mid-2026 reviews describe Local API access as paid-plan only; verify on the current plan page rather than on those reviews.

Incogniton wraps its local API in ergonomic Python and Node SDKs with a startPlaywright() one-liner, which is the fastest path if you already work in those languages. It is wrong for polyglot infrastructure, since its browser-automation layer is documented as SDK-exclusive rather than reachable over plain HTTP.

What this does not solve

An antidetect profile changes what the browser reports about itself. It does not change how the thing driving the browser behaves, and behaviour is where most modern detection lives. A profile with a flawless fingerprint that requests two hundred product pages in ninety seconds with no scrolling, no mouse movement and perfectly uniform intervals will be caught by an anti-bot system that never looks at canvas hashes at all. The reasons scrapers get blocked are mostly not fingerprint reasons; why scrapers get blocked goes through the full list.

It also does not make this the right tool for most collection work. A full browser per identity is the most expensive way to fetch a page, in memory, in licence cost and in engineering time. Reach for it when the target genuinely requires a persistent logged-in identity, or when the anti-bot layer defeats everything cheaper. For everything else, an API that returns rendered HTML is a better trade, and the 2026 web scraping stack post covers where each layer belongs.

If you have already decided you need one, drive it from code. The licence you are paying for includes an API, and the profile grid is the slowest way to use it.

Frequently asked

Which antidetect browsers expose a local automation API?
All seven of the major ones do. Kameleo, Multilogin, AdsPower, Octo Browser, GoLogin, Dolphin Anty and Incogniton each ship a local HTTP API that starts a profile and hands back a debugging endpoint. What differs is which plan reaches it. AdsPower's Local API overview, read on 27 July 2026, states that API permission goes to accounts on a paid version. Multilogin's pricing page on the same date includes API access from Pro 10 upward and excludes the free tier. Third-party reviews from mid-2026 describe Dolphin Anty's Local API as paid-plan only. Check the current plan page before you build.
How do I attach Playwright to an antidetect browser profile?
Send the vendor's start request, parse the endpoint out of the response, then call chromium.connect_over_cdp() with it. Kameleo's docs use ws://localhost:5050/playwright/{profileId}. Multilogin's launcher returns a port you turn into an http://127.0.0.1:{port} CDP address. AdsPower returns data.ws.puppeteer, which Playwright accepts directly. Octo Browser returns a ws_endpoint when you launch with debug_port set. After connecting, take the existing context with browser.contexts[0] rather than calling new_context(), which would discard the profile's cookies and storage.
How many profiles can I run concurrently?
Your licence decides before your hardware does. Kameleo bills a Concurrent Browsers Limit directly: its pricing page in July 2026 listed 2 on the free tier, 10 on Startup, 100 on Business and 1,000 on Enterprise, with paid add-on blocks above that. Other vendors constrain you indirectly through stored profile counts, seats and API requests per minute. AdsPower's Local API docs tie request rate to stored profile count: 2 per second under 200 profiles, 5 up to 5,000, 10 above that. Machine limits matter too: a Chromium instance with a visible window is roughly 300MB to 700MB of RAM.
Should each profile have its own proxy?
Yes, and it should be the same exit IP every time that profile runs. The whole premise of an antidetect profile is a consistent identity, and an identity whose network location changes between sessions is less coherent than a plain browser. Bind a sticky residential or mobile IP per profile at profile-creation time, store the mapping alongside the profile definition, and treat a proxy rotation as a profile retirement. Shared datacenter ranges across many profiles reintroduce exactly the correlation that separate fingerprints were meant to remove.
How do I version and back up browser profiles?
Version the definition, back up the state, and keep them separate. The definition is fingerprint parameters, proxy binding, browser engine and start flags: put that in git as JSON or YAML so any profile can be rebuilt from scratch. The state is cookies, local storage and IndexedDB, which cannot be regenerated once a login ages into a trusted session. Export that on a schedule to object storage with retention. GoLogin's SDK uploads profile state on exit, and Kameleo supports profile export, but a vendor-side copy is not a backup you control.

Weekly briefing – tool launches, legal shifts, market data.