Logo of Lexmount
DocsTemplatesBlogHelp Center
GitHub
Logo of LexmountLexmount Browser

Get started

Lexmount Documentation
Console guide

Browser

OverviewQuickstartCapabilitiesExamples

Web Fetch

OverviewQuick Start
Common Errors

Web Search

OverviewQuick StartSearch API

Runtime

OverviewQuickstartCapabilitiesExamples

Help and billing

Capability FAQ
ChangelogContact support
Python SDK

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},
)
OptionPurpose
browser_modenormal for Chromium or light for Moli
context / context_descriptionReuse or create persistent browser state
extension_idsMount uploaded extensions
proxy / official_proxySelect a local, external, or official proxy
downloadsEnable or disable stored session downloads
recordingEnable or disable persistent replay; forced off for Moli
custom_image_idStart an approved custom browser image
window_sizeSet ACE browser size as width,height
enable_lightmount_layoutEnable the LightMount layout integration; defaults to True
enable_lightmount_resourceOverride layout-resource integration for this session
enable_captchaRequest automatic CAPTCHA processing for this session; disabled by default
async_createUse async create and wait for active; defaults to True
poll_interval_sec / poll_timeout_secControl 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=3000

Session 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.com

Use 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.

OperationCall
Read / list Agentsagents.get(id) / agents.list()
Edit an Agentagents.update(id, revision=current.revision, name="Updated name")
Delete an Agentagents.delete(id)
Read / list Runsruns.get(id) / runs.list()
Request cancellationruns.cancel(id)
Wait for terminal stateruns.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_key as 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, and cancelled are terminal Run results. HTTP success alone does not mean the task succeeded; inspect status, stop_reason, error, and output.
  • RunWaitTimeout only stops local polling. Resume with the known Run ID, or explicitly request cancellation. timeout, poll_interval, and request_timeout use seconds.
  • APIError includes status_code, code, and request_id. Keep the request ID for support. Pass with_response=True to 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.credits can be None while 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.

Python Quick Start

Create Chromium and Moli sessions and connect to Chromium with Playwright.

Python Examples

Choose a runnable Python quickstart script by browser task.

Table of Contents

Client and regions
Sessions
Create options
Automatic CAPTCHA processing
Read, list, targets, and close
Downloads
Local Proxy Tunnels
Contexts
Extensions
CDP helpers and integrated authentication
Errors and logs
Opt-in quality reporting
Browser Agent
Setup
Run a task
Reuse a saved Agent
Manage resources
Recovery and errors
Async client

Still need help?Ask on Discord