Skip to content

Local or cloud: one SDK

The same launch() that starts Clearcote on your machine starts it on our servers. Pass cloud=True (Python) or cloud: true (Node), or set CLEARCOTE_CLOUD=1, and you get the same Playwright Browser back, connected to a hosted browser. The rest of your script stays as it is.

Run a script in the cloud

You need SDK 0.34.0 or newer and an API key from the API keys page. Put the key in CLEARCOTE_API_KEY, then:

from clearcote import launch

browser = launch(cloud=True, fingerprint="acct-1", country="de")
page = browser.contexts[0].new_page()
page.goto("https://example.com")
print(page.title())
browser.close()   # ends the cloud session

Behind the call, the SDK creates a session with POST /api/v1/browsers, connects to it over CDP and sets up humanize the way a local launch does. Open pages in browser.contexts[0]: it carries the session's profile. browser.new_page() works too, but opens a separate context without the profile's cookies (the SDK still turns off Playwright's emulated viewport for it, as it does locally).

The hosted session behind the browser is on browser.cloud_session in Python and cloudSessionOf(browser) in Node (also browser.cloudSession): the create answer with its id, worker and expiresAt, minus the single-use connectUrl. Use the id with the Cloud client for hand-off, recordings and events.

Switch with environment variables

Leave cloud out of the call and the environment decides, so one script runs locally on your laptop and in the cloud in production without a code change.

VariableMeaning
CLEARCOTE_CLOUD1, true or yes: a launch() without a cloud argument starts a cloud browser. Anything else, or unset: a local one.
CLEARCOTE_API_KEYYour cc_live_… key. Needed for every cloud call.
CLEARCOTE_API_URLThe API to talk to. Default https://www.clearcotelabs.com; change it only for a development control plane. It must be https://; plain http:// is only accepted for this machine (localhost, 127.0.0.1, ::1), so the key never crosses a network unencrypted.
bash
export CLEARCOTE_API_KEY=cc_live_...

python scrape.py                     # a local browser
CLEARCOTE_CLOUD=1 python scrape.py   # the same script on a hosted browser

An explicit argument always wins: cloud=False / cloud: false launches locally whatever CLEARCOTE_CLOUD says.

Options

In cloud mode, launch() takes the options of POST /api/v1/browsers. Node uses the API's names as they are; Python uses snake_case, and the SDK renames them. The full rules for each option are in the hosted browsers reference.

PythonNode and APIMeaning
identityidentityOne label per account: the same device and the same residential IP while that IP stays online.
fingerprintfingerprintDevice seed. The same seed gives the same device profile.
light_stealthlightStealthDefault true.
platformplatformwindows, macos, linux or android.
brandbrandChrome, Edge, Opera or Vivaldi.
timezonetimezoneIANA name, for example Europe/Berlin.
locale, accept_languagelocaleAccept-Language, for example de-DE,de. accept_language (Node: acceptLanguage) is an alias.
geoipgeoipTimezone and language follow the exit IP.
proxyproxy"managed" (the default), { server, username, password }, or a URL such as http://user:pass@host:8080, which the SDK splits into that object for you.
countrycountryExit country in the managed residential pool.
statestateExit state or region in the managed pool. Needs country.
citycityExit city in the managed pool. Needs state.
proxy_sessionproxySessionSticky label: the same label gets the same exit IP back later.
timeout_sectimeoutSecHard limit on the session length, in seconds.
idle_timeout_secidleTimeoutSecEnd the session after this long without a CDP command.
max_gbmaxGbStop the session after this much traffic.
headlessheadlessDefault true.
keep_alivekeepAliveKeep the browser running after you disconnect.
versionversionRun a specific Clearcote release.
profileprofileA cloud profile: "name" to load it, { name, persist: true } to also save it back.
urlurlOpened in the first tab before you get the browser.
adblockadblockRefuse known ad and tracker hosts before they load.
recordrecordRecord an MP4 of the session.
notenoteYour label for the session.
workerworkerStart on the same server as an earlier session.
humanizehumanizeHuman mouse and keyboard, applied by the SDK on your side. Never sent to the API.
show_cursorshowCursorShow a red dot that follows the mouse, for watching or debugging. SDK side, like humanize.
api_key, api_urlapiKey, apiUrlThe account and API server for this launch. Default CLEARCOTE_API_KEY and CLEARCOTE_API_URL. Never sent as options.
timeout, slow_motimeout, slowMoPlaywright's own options for the CDP connection, in milliseconds. Not sent to the API.

What stays the same, what differs

The same:

  • You get a Playwright object. launch() returns a Browser and launch_persistent_context() a BrowserContext, sync or async, exactly as locally.
  • Humanize runs on your side either way. The SDK installs the same curved mouse paths and key-by-key typing on the cloud browser as on a local one, so humanize behaves identically. It is never sent to the API.
  • The same engine. Hosted sessions run the same Clearcote releases the SDK downloads, so the persona options mean the same thing in both places, and version pins the same build.

Different:

  • Local-only options are refused. executable_path, args, user_data_dir, extensions, ignore_default_args and the other options that only make sense for a binary on your machine raise ValueError("<name> is not available for cloud browsers") in Python (an error with the same message in Node) rather than being ignored.
  • Profiles instead of folders. A cloud browser has no folder on your disk. To keep cookies and site storage between runs, use a named cloud profile (below).
  • profile means a cloud profile. Locally, profile picks a captured device profile ("auto"). In cloud mode it names a saved cloud profile: cookies, localStorage and IndexedDB.
  • Hosted defaults. A cloud session starts from the hosted defaults: lightStealth on, a seed, timezone and language that follow the exit IP, and a residential exit IP unless you pass your own proxy.
  • Closing. browser.close() disconnects, and the session ends when its client goes; the SDK also stops it through the API to be sure. With keep_alive / keepAlive the browser keeps running instead, until you stop it or a limit does.
  • Hosted limits. No file://, no extensions, no private networks, downloads stay on the server, and page.on("console") stays silent. See the limits.
  • Billing. A cloud browser is billed like any hosted session, per GB of traffic from your prepaid balance. A local browser costs nothing beyond your licence.

A persistent context on a cloud profile

launch_persistent_context() with cloud=True takes a profile name instead of a folder. It returns the first context of a cloud session started with profile: { name, persist: true }: the session loads the profile, and closing the context ends the session and saves cookies and site storage back to it.

from clearcote import launch_persistent_context

ctx = launch_persistent_context(cloud=True, profile="shop-account", country="de")
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.goto("https://shop.example.com/account")
ctx.close()   # ends the session and saves "shop-account"

Passing a user_data_dir together with cloud=True raises a ValueError that points you at profile=. Only one session at a time can save to a profile. To start a profile from cookies you already have, use cookie sync.

The Cloud client

Everything else the API does has a client: sessions, agent runs, profiles and webhooks. It reads CLEARCOTE_API_KEY and CLEARCOTE_API_URL, or takes them as arguments. The Python client uses only the standard library; AsyncCloud has the same methods for asyncio.

from clearcote.cloud import Cloud, CloudError

cloud = Cloud()   # or Cloud(api_key="cc_live_...", base_url="https://www.clearcotelabs.com")

session = cloud.browsers.create(country="de", record=True)
print(session["id"], session["connectUrl"])

try:
    cloud.browsers.stop(session["id"])
except CloudError as e:
    print(e.status, e.code, e.message)
NamespaceMethods
browserscreate(**options), get(id), list(status=None, note=None, limit=None, before=None), stop(id), live(id, control=False), share(id, control=None, minutes=None, recording=None), handoff(id, reason=None, timeout_sec=None), handoff_done(id), wait_handoff(id, timeout=None, poll=2.0), events(id, after=0, limit=None), recording_url(id), download_recording(id, path)
runscreate(task, url=None, schema=None, secrets=None, wait=True, timeout=None, poll=1.5, on_update=None, **options), get(id), list(limit=None, before=None), cancel(id), wait(id, timeout=None, poll=1.5, on_update=None)
profileslist(), get(name), delete(name), import_cookies(name, cookies, mode="merge"), sync(name, …)
webhookscreate(url, events=None, description=None), list(), delete(id), test(id)

Every method returns the endpoint's JSON as it is: a dict in Python, a plain object in Node. List calls return the API's object, for example { balanceEur, sessions } or { runs }, not a bare list. Durations the SDK waits itself (timeout, poll) are in seconds in both languages.

Node has the same methods in camelCase (handoffDone, waitHandoff, importCookies, recordingUrl, downloadRecording), with the optional arguments in one object: live(id, { control }), events(id, { after, limit }), runs.create(task, { url, schema, country, … }), importCookies(name, cookies, { mode }), webhooks.create(url, { events }). A failed call raises CloudError with the HTTP status (0 when the API could not be reached), the API's code and its message; the codes are listed under Errors. A wait that runs past its timeout raises CloudTimeoutError instead, whose last holds the last state the SDK read; the run or hand-off carries on on the server. A bad option raises ValueError in Python (an Error in Node) before anything is sent. The SDK also exports verify_webhook / verifyWebhook for webhook signatures.

The clearcote cloud command

The clearcote command that comes with the SDK (pip install clearcote, or npx clearcote) has a cloud group for the same API:

bash
# an agent run: prints the result when it finishes
clearcote cloud run "Find the price of the cheapest plan" --url https://example.com/pricing \
  [--schema schema.json] [--secret name=value]... [--secret-domain name=host]... [--handoff] [--record] [--json]

# sessions
clearcote cloud sessions
clearcote cloud stop <id>
clearcote cloud events <id>
clearcote cloud recording <id> -o session.mp4

# copy cookies into a cloud profile (--domain or --all-domains is required)
clearcote cloud profile sync <name> (--from-profile DIR | --from-cdp URL | --from-file state.json | --login URL) \
  (--domain example.com... | --all-domains) [--replace]

# webhooks
clearcote cloud webhooks add https://example.com/hooks/clearcote [--event run.finished]...
clearcote cloud webhooks list
clearcote cloud webhooks rm <id>
clearcote cloud webhooks test <id>

Every command takes --json to print the API's answer instead of a summary. run waits for the result and exits with 0 only when the run succeeded (1 otherwise, 2 for a usage error), so it works in a shell script. recording saves to <id>.mp4 without -o. Run clearcote cloud --help for every flag.

Each command is covered on its own page: runs, recordings and events, profile sync and webhooks.

MCP: a cloud browser for your AI assistant

The MCP server has the same switch. With CLEARCOTE_CLOUD=1 and CLEARCOTE_API_KEY in its env, the shared browser its tools drive is a cloud browser. With an API key set, it also gets a run_task tool that hands a whole task to an agent run and returns the result JSON.

json
{
  "mcpServers": {
    "clearcote": {
      "command": "npx",
      "args": ["-y", "clearcote-mcp"],
      "env": { "CLEARCOTE_CLOUD": "1", "CLEARCOTE_API_KEY": "cc_live_..." }
    }
  }
}