Teams on GoLogin or AdsPower often already automate via local HTTP API + CDP. Migrating to Multilogin is mostly an adapter swap — launch/stop endpoints change; Playwright/Puppeteer attach stays the same. This recipe shows both vendor patterns and a safe migration path.

Universal CDP adapter (Python)

from enum import Enum
import httpx
from playwright.async_api import async_playwright

class Vendor(str, Enum):
    MULTILOGIN = "multilogin"
    GOLOGIN = "gologin"
    ADSPOWER = "adspower"

CONFIG = {
    Vendor.MULTILOGIN: {"base": "https://api.multilogin.com", "start": "/profile/start", "stop": "/profile/stop", "id_key": "profile_id"},
    Vendor.GOLOGIN:    {"base": "http://127.0.0.1:36912",    "start": "/browser/start-profile", "stop": "/browser/stop-profile", "id_key": "profileId"},
    Vendor.ADSPOWER:   {"base": "http://local.adspower.net:50325", "start": "/api/v1/browser/start", "stop": "/api/v1/browser/stop", "id_key": "user_id"},
}

async def launch_cdp(vendor: Vendor, profile_id: str, token: str | None = None) -> str:
    cfg = CONFIG[vendor]
    headers = {"Authorization": f"Bearer {token}"} if token else {}
    payload = {cfg["id_key"]: profile_id}
    async with httpx.AsyncClient(timeout=90) as client:
        r = await client.post(f"{cfg['base']}{cfg['start']}", json=payload, headers=headers)
        r.raise_for_status()
        data = r.json()
    # normalize CDP URL across vendors
    return data.get("cdp_url") or data.get("wsUrl") or data["data"]["ws"]["puppeteer"]

async def with_browser(vendor: Vendor, profile_id: str, fn, token: str | None = None):
    cdp = await launch_cdp(vendor, profile_id, token)
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(cdp, timeout=60_000)
        try:
            ctx = browser.contexts[0] if browser.contexts else await browser.new_context()
            page = ctx.pages[0] if ctx.pages else await ctx.new_page()
            await fn(page)
        finally:
            await browser.close()
            cfg = CONFIG[vendor]
            async with httpx.AsyncClient() as client:
                await client.post(f"{cfg['base']}{cfg['stop']}", json={cfg["id_key"]: profile_id}, headers=headers if token else {})

Endpoint paths vary by vendor version — verify local API docs. Multilogin cloud API uses bearer token; GoLogin/AdsPower typically run desktop app locally.

GoLogin local API notes

AdsPower local API notes

Migration runbook (7 steps)

  1. Inventory — CSV: old_profile_id, platform, geo, proxy, last_login, ban_status
  2. Cookie export — while still logged in on old vendor; see profile transfer guide
  3. Create Multilogin profiles — match timezone, WebGL, language to old fingerprint audit
  4. Proxy re-bind — same sticky session if possible; never swap mid-session (proxy alignment)
  5. Smoke test — 5 prod accounts, manual login + one automated flow each
  6. Adapter deploy — env var ANTIDETECT_VENDOR=multilogin in CI workers
  7. Decommission — archive old profiles after 14-day parallel run; update CMDB IDs

When migration makes sense

SignalMultilogin advantage
Team workspace + client separationRole-based access, agency workflows
Cloud API without desktop GUI on workersHeadless profile start from Linux CI
Mimic + Stealthfox engine choicePlatform-specific engine tuning
API rate limits on local-only toolsCentralized cloud launch at scale

Fair comparison: GoLogin and AdsPower remain valid for solo operators and budget stacks. See full comparison and CDP migration recipe.

Related recipes

Disclosure: MLX-MMO affiliated with Multilogin. Vendor APIs change; verify GoLogin, AdsPower, and Multilogin docs before deploy.