Python Capabilities
Current client, session, context, extension, download, CDP, Browser Agent, error, and logging APIs.
Client and regions
from lexmount import Lexmount
client = Lexmount(
region="<region-id>",
timeout=60.0,
)
print(client.region_info())
print(client.catalog_info())The client reads credentials from constructor arguments or environment variables. Region catalog discovery is best effort: an unavailable catalog or probe falls back to the configured base URL.
Sessions
Create options
session = client.sessions.create(
browser_mode="normal",
window_size="1920,1080",
downloads={"enabled": True},
recording={"persistent": True},
)| Option | Purpose |
|---|---|
browser_mode | normal for Chromium or light for Moli |
context / context_description | Reuse or create persistent browser state |
extension_ids | Mount uploaded extensions |
proxy / official_proxy | Select a local, external, or official proxy |
downloads | Enable or disable stored session downloads |
recording | Enable or disable persistent replay; forced off for Moli |
custom_image_id | Start an approved custom browser image |
window_size | Set ACE browser size as width,height |
enable_lightmount_layout | Enable the LightMount layout integration; defaults to True |
enable_lightmount_resource | Override layout-resource integration for this session |
enable_captcha | Request automatic CAPTCHA processing for this session; disabled by default |
async_create | Use async create and wait for active; defaults to True |
poll_interval_sec / poll_timeout_sec | Control activation polling |
official_proxy=True and proxy={...} are mutually exclusive. Plan capabilities determine whether contexts, extensions, proxies, and custom images are available.
Automatic CAPTCHA processing
Use SDK 0.6.1 or later and explicitly opt in when creating a session:
with client.sessions.create(
browser_mode="normal",
enable_captcha=True,
) as session:
print(session.id)The default is False. This preference applies only to the new session; other sessions in the same project can remain disabled. The SDK sends the top-level enable_captcha boolean in both synchronous and asynchronous create requests.
The service automatically detects and processes CAPTCHAs for opted-in sessions with eligible project access. Availability and usage depend on the project's plan and remaining CAPTCHA allowance. Continue controlling the browser with the existing SDK or CDP connection.
See session lifecycle for the corresponding console option.
Read, list, targets, and close
current = client.sessions.get(session.id)
sessions = client.sessions.list(status="active")
print(sessions.pagination.total_count)
for item in sessions:
print(item.id, item.status, item.region_id, item.browser_type)
for target in client.sessions.list_targets(session.id):
print(target.title, target.url, target.inspect_url)
session.close()
# Equivalent when only the ID is available:
client.sessions.delete(session_id=session.id)Downloads
result = client.sessions.downloads.list(session.id)
print(result.summary["count"], result.summary["total_size"])
file_bytes = client.sessions.downloads.get(session.id, "<download-id>")
archive_bytes = client.sessions.downloads.archive(session.id)
deleted = client.sessions.downloads.delete(session.id)
print(deleted.deleted_count)Stored downloads are enabled by default. Configure the remote browser download path as shown in the quickstart repository so files reach the persistent download directory.
Local Proxy Tunnels
SDK 0.6.0 introduced client.tunnels.open(); use 0.6.1 or later. Once ready, create a normal session with proxy={"type": "local", "tunnel_id": tunnel.id} to use the SDK machine's network and DNS. This requires custom_proxy, the same project/Key/region, and excludes official or external proxy. Close the session before the tunnel. See the local proxy guide for complete examples and options.
Contexts
context = client.contexts.create(
description="Authenticated storefront",
metadata={"owner": "agent-a"},
)
session = client.sessions.create(
context={"id": context.id, "mode": "read_write"},
)
contexts = client.contexts.list(status="available", limit=20)
details = client.contexts.get(context.id)
forked = client.contexts.fork(context.id)
client.contexts.force_release(context.id)
client.contexts.delete(forked.id)A context used by an active read-write session is locked. Current fork behavior copies an offline available context; hot fork, copy-on-write, and lineage tracking are not supported.
Extensions
extension = client.extensions.upload(
"/absolute/path/to/extension.zip",
name="demo-extension",
)
extensions = client.extensions.list(limit=20, offset=0)
details = client.extensions.get(extension.id)
session = client.sessions.create(extension_ids=[extension.id])
session.close()
client.extensions.delete(extension.id)The service accepts .zip and .crx archives. An extension cannot be deleted while an active session uses it.
CDP helpers and integrated authentication
from lexmount import Lexmount, connect_over_cdp
client = Lexmount()
session = client.sessions.create()
cdp = connect_over_cdp(session)
print(cdp.send("Browser.getVersion"))
cdp.close()
session.close()
client.close()The SDK also exports register_integrated_auth_callback. NTLM and Kerberos callback factories are available from the optional lexmount-extra package.
Errors and logs
from lexmount import (
APIError,
AuthenticationError,
ContextLockedError,
NetworkError,
TimeoutError,
set_log_level,
)
set_log_level("INFO")
try:
session = client.sessions.create()
except AuthenticationError:
print("Check API Key and Project ID")
except ContextLockedError as error:
print(error.active_session_id, error.retry_after)
except (NetworkError, TimeoutError):
print("Retry only after checking whether a session was reserved")
except APIError as error:
print(error.status_code)Opt-in quality reporting
Quality reporting is disabled by default and never changes user-facing errors. Enable it only when the project has approved telemetry collection:
LEXMOUNT_QUALITY_REPORTING_ENABLED=true
LEXMOUNT_QUALITY_CDP_SLOW_THRESHOLD_MS=3000Session create failures and summaries can be reported by the SDK. Individual CDP latency events are available only when commands use the SDK connect_over_cdp() helper.
Browser Agent
Browser Agent executes a browser task from a natural-language instruction. A Run is one execution; a saved Agent holds a reusable instruction and optional output schema. Use client.browser_agent with SDK 0.7.0.
Setup
pip install lexmount==0.7.0
export LEXMOUNT_API_KEY='<your-api-key>'
export LEXMOUNT_PROJECT_ID='<your-project-id>'
# Optional: SDK 0.7.0 defaults to this global COM origin.
export LEXMOUNT_BASE_URL=https://api.lexmount.comUse an API Key and Project ID from the same project, with Browser Agent enabled in the selected environment. Set the HTTPS origin, without /v1/browser-agent; the SDK adds that path. Set https://api.lexmount.cn explicitly for CN. Playwright is not required for these Agent API calls.
Run a task
Choose and persist a new RUN_IDEMPOTENCY_KEY for one logical task before running this example. Reuse it with the identical request when recovering that task; use a new key for an intentionally new task.
export RUN_IDEMPOTENCY_KEY='<persistent-unique-key-for-this-task>'Save as agent.py and run python agent.py:
import os
from lexmount import APIError, Lexmount, RunWaitTimeout
key = os.environ["RUN_IDEMPOTENCY_KEY"]
try:
with Lexmount() as client:
receipt = client.browser_agent.runs.create(
query="Read the page title and summarize the page.",
start_url="https://example.com/",
idempotency_key=key,
)
print("Accepted:", receipt.id) # Save this Run ID before waiting.
run = client.browser_agent.runs.wait(receipt.id, timeout=300)
print(run.id, run.status, run.output)
if run.status != "succeeded":
print(run.stop_reason, run.error)
raise SystemExit(1)
except RunWaitTimeout as error:
print("Resume with runs.get/wait:", error.run_id)
raise SystemExit(1)
except APIError as error:
print(error.status_code, error.code, error.request_id)
raise SystemExit(1)A create response is a queued receipt, not a completed result. Save receipt.id and use runs.get(id) or runs.wait(id) to recover after a process restart. Closing the SDK client does not cancel an active Run.
Reuse a saved Agent
Set two additional persistent keys, AGENT_IDEMPOTENCY_KEY for the Agent creation and SAVED_RUN_IDEMPOTENCY_KEY for this Run. Save the returned Agent ID and use it for later Runs; creating the Agent is a one-time setup step.
import os
from lexmount import Lexmount
with Lexmount() as client:
agent = client.browser_agent.agents.create(
name="Page summary",
instruction="Summarize the page in {{language}}.",
start_url="https://example.com/",
output_schema={
"type": "object",
"properties": {"summary": {"type": "string"}},
"required": ["summary"],
"additionalProperties": False,
},
idempotency_key=os.environ["AGENT_IDEMPOTENCY_KEY"],
)
receipt = client.browser_agent.runs.create(
agent_id=agent.id,
variables={"language": "English"},
metadata={"source": "docs"},
idempotency_key=os.environ["SAVED_RUN_IDEMPOTENCY_KEY"],
)
print("Agent:", agent.id, "Run:", receipt.id)
# Recover this Run later with runs.get(receipt.id) or runs.wait(receipt.id).Supply exactly the instruction's template variables. The accepted Run freezes the Agent revision, expanded instruction and schema; later Agent edits do not change that Run. metadata is returned to your application and is not sent to the model. A successful schema-based output is an object; free-form output is text.
Manage resources
All methods below are on client.browser_agent. For AsyncLexmount, await each call.
| Operation | Call |
|---|---|
| Read / list Agents | agents.get(id) / agents.list() |
| Edit an Agent | agents.update(id, revision=current.revision, name="Updated name") |
| Delete an Agent | agents.delete(id) |
| Read / list Runs | runs.get(id) / runs.list() |
| Request cancellation | runs.cancel(id) |
| Wait for terminal state | runs.wait(id) |
Read the current Agent first and pass its revision when updating. A revision conflict requires reading it again; updates are not automatically retried. Cancellation can race with completion: inspect the returned state and keep reading until terminal if it is still cancelling.
Recovery and errors
- The SDK generates an idempotency key if omitted. For recovery across process restarts, supply your own:
idempotency_keyas a keyword argument. Persist the key and request body before sending; use 1–128 visible ASCII characters without spaces. Same key/body replays the original receipt for at least seven days; a different body conflicts. Beyond that window, reconcile through history before creating anything again. succeeded,failed,timed_out, andcancelledare terminal Run results. HTTP success alone does not mean the task succeeded; inspectstatus,stop_reason,error, andoutput.RunWaitTimeoutonly stops local polling. Resume with the known Run ID, or explicitly request cancellation.timeout,poll_interval, andrequest_timeoutuse seconds.APIErrorincludesstatus_code,code, andrequest_id. Keep the request ID for support. Passwith_response=Trueto get success response metadata.- Keep the API Key used to create a Run valid until execution and cleanup finish. Revoking it can fail an active Run with
credential_unavailable; changing the client's key does not replace the original Run's execution credential. usage.creditscan beNonewhile metering is pending; it does not mean zero cost. Task execution may have external side effects, so an unknown result must not be blindly resubmitted.
Async client
Use AsyncLexmount for the same resources. This example reads an existing Run; set RUN_ID to its saved ID.
import asyncio
import os
from lexmount import AsyncLexmount
async def main():
async with AsyncLexmount() as client:
run = await client.browser_agent.runs.get(os.environ["RUN_ID"])
print(run.id, run.status, run.output)
asyncio.run(main())Runnable examples cover basic execution, saved Agents and recovery.
