Browser API: functions and examples
Connect through Python, Node.js, Java, or Go. This reference covers profile configuration, browser sessions, page observation, input, files, and saved Skills, following the GitHub API examples.
Install and make your first call
pip install kingai-browser
python -m kingai_browser installSign in to your KingAI account and prepare the unique saved profile named 默认环境. The example starts that profile, reads a page, and releases control while keeping the browser window open. To select a different saved profile, pass its real profile_id to api.start().
from kingai_browser import KingAI
with KingAI() as api:
browser = api.start()
try:
browser.goto("https://www.kingaibrowser.cn/")
print(browser.read())
finally:
browser.detach()Each recipe below is independent, not a script to run from top to bottom. Select the operation you need and substitute real profile, session, element, and Skill IDs. The snippets illustrate the documented API; they are not a claim that every operation has been tested on your target site.
- Calling conventions and four languages
- Profiles and configuration
- Starting, attaching, and ownership
- Tabs and navigation
- Reading, snapshots, and DOM queries
- Waiting, clicking, typing, and scrolling
- JavaScript evaluation and bounded previews
- Screenshots, PDF, and file transfer
- Cookies and Storage
- Saved Skill workflows
- The installed tool catalog
- Errors and execution results
01 · Calling conventions and four languages
Python, Node.js, Java, and Go share tool names and raw JSON fields. Session-level call methods inject session_id; raw field names are not converted to camelCase. Later recipes use Python, with api as a connected KingAI client and browser as a running session.
| Function / call | Purpose |
|---|---|
launch() | Connect and start a profile, returning a BrowserSession; for ordinary Python scripts. |
KingAI | Explicit client ownership, profile CRUD, tool discovery, and session management. |
BrowserAutomation | An Agent action and state facade over the same SDK, for Agent adapters. |
agent_browser.execute(action, **arguments) | Dispatch actions such as go_to_url, query, click_element, input_text, extract_content, or mcp_call. Element actions require an observed ref or exact selector. |
agent_browser.get_current_state() | Observe the live page, snapshot, and tabs; return a state dictionary including interactive_elements, not a cached lookup. |
agent_browser.describe_error(error) | Describe an error as structured information for the Agent adapter. |
agent_browser.close() | Disconnect the facade’s MCP connection and keep the window open, as does context exit; distinct from session close_browser(). |
browser.call(name, **arguments) | Python session-level tool call. |
await browser.call(name, arguments) | Node.js: await every operation. |
browser.call(name, Map.of(...)) | Java: returns a Jackson JsonNode. |
browser.Call(ctx, name, kingai.Arguments{...}) | Go: pass a context and handle the returned error. |
BrowserAutomation: Agent actions and state
These entry points are layers of one SDK using the same installed MCP/Runtime, not three browser engines. Import BrowserAutomation from kingai_browser. It dispatches actions and collects state; it is not an AI model or autonomous planner. Page-changing actions collect follow-up observations. Failed observation never automatically replays input, and the Agent must assess business success from the page.
import json
from kingai_browser import BrowserAutomation
with BrowserAutomation(profile_id="actual-saved-profile-id") as agent_browser:
# Replace the ID with one from KingAI.profiles(); do not invent one.
result = agent_browser.execute("go_to_url", url="https://example.com")
state = agent_browser.get_current_state()
print(state["url"], state["title"])
snapshot = json.loads(state["interactive_elements"])
for element in snapshot.get("elements", []):
print(element.get("ref"), element.get("name"))
# Query through the facade rather than guessing an element index.
links = agent_browser.execute("query", arguments={"selector": "a", "limit": 10})
print(links)Real IDs, session reuse, and OpenManus
Replace the example profile ID with one returned by KingAI.profiles(); omit profile_id only to use the unique existing default. Resume through BrowserAutomation(session_id="actual-active-session-id") only when attaching is permitted, without also passing profile_id. Reuse query()/snapshot() on an existing BrowserSession instead of starting another facade. OpenManus browser_use is a tool name whose implementation delegates to BrowserAutomation.execute() and get_current_state(); it is not the SDK class itself.
Generic calls in four languages
Python
# Python: arbitrary installed tool; keyword arguments bind to the current session.
result = browser.call("browser_query", selector="#name", include_html=True)Node.js
// Node.js: same tool and raw arguments; await every operation.
const result = await browser.call('browser_query', { selector: '#name', include_html: true });Java
// Java: Session.call injects session_id, Jackson JsonNode is returned.
JsonNode result = browser.call("browser_query", Map.of("selector", "#name", "include_html", true));Go
// Go: Session.Call injects session_id. Always propagate the returned error.
result, err := browser.Call(ctx, "browser_query", kingai.Arguments{"selector": "#name", "include_html": true})
if err != nil { return err }02 · Profiles and configuration
Creating or updating a profile does not start a browser. Names must be unique. Close the profile before updating it; group_name must identify an existing group. A patch merges objects recursively and replaces arrays. Delete only a profile you explicitly intend to remove.
| Function / call | Purpose |
|---|---|
api.profiles() | List saved profile summaries. |
api.create_profile(name, language="en-US") | Create a profile and return its profileId. |
api.profile(profile_id) | Read a saved profile. |
api.update_profile(profile_id, name=..., patch=...) | Update the name and configuration. |
api.delete_profile(profile_id, confirm=True) | Explicitly delete a closed profile. |
Python
saved = api.profiles() # profiles_list: saved summaries
created = api.create_profile("Unique example", language="en-US")
profile_id = created["profileId"] # ID returned by creation
summary = api.profile(profile_id) # profiles_get
api.update_profile(profile_id, name="Configured example", patch={
"locale": {"language": "en-US", "accept_languages": "en-US,en"}
})
updated = api.profile(profile_id)
# Optional, destructive: only after explicitly closing this environment.
# api.delete_profile(profile_id, confirm=True)03 · Starting, attaching, and ownership
api.start() uses the unique saved profile named 默认环境. A missing default is an error, never a silent temporary-profile fallback. Temporary mode requires temporary=True. Attaching is subject to server ownership rules; inspect sessions after a disconnect. Python with launch() and Java automatic Session.close() detach owned connections and preserve windows. Explicit browser shutdown uses Python close_browser()/close(), Node.js closeBrowser()/close(), Java closeBrowser(), or Go CloseBrowser()/Close(). Methods named close do not have identical ownership semantics across languages.
| Function / call | Purpose |
|---|---|
api.start(profile_id=..., headless=False) | Start a saved profile and return a browser session. |
api.sessions() | Inspect active sessions. |
api.attach(session_id) | Attach when ownership rules permit. |
browser.detach() | Release control and preserve the browser window. |
browser.close() / browser.close_browser() | Python: explicitly close the browser. |
api.close() | Close this client’s MCP connection. |
Python
browser = api.start(profile_id=profile_id, headless=False)
session_id = browser.session_id
active = api.sessions() # inspect real active sessions
# Another client can request attach only if server ownership rules allow it:
# browser = api.attach(session_id)
browser.detach() # leave browser available
# browser.close() # explicitly close the browser
# api.close() # only close this client's MCP04 · Tabs and navigation
Operations target the selected tab. Serialize tab switches and input; a session is not a concurrent multi-Page model. Use a real returned targetId and close only the intended tab. The local demo.html URL in the recipe requires your own running demo page.
| Function / call | Purpose |
|---|---|
browser.new_tab(url) | Open a tab and read its returned targetId. |
browser.tabs() | List tabs. |
browser.activate_tab(target_id) | Activate a tab. |
browser.goto(url) | Navigate the selected tab. |
browser.close_tab(target_id) | Explicitly close a tab. |
Python
opened = browser.new_tab("http://127.0.0.1:8765/demo.html")
target_id = opened["targetId"]
all_tabs = browser.tabs()
browser.activate_tab(target_id)
browser.goto("http://127.0.0.1:8765/demo.html")
# Explicitly close ONLY a tab you created and no longer need:
# browser.close_tab(target_id)05 · Reading, snapshots, and DOM queries
For ordinary Python automation, call query() and snapshot() on your current session after opening a page. No browser_state object or Agent framework is required. Unfiltered query() enumerates bounded DOM summaries; snapshot(mode="interactive") focuses on interaction candidates, while the default compact snapshot can also include contextual text and structure.
| Function / call | Purpose |
|---|---|
browser.read() | Read page content. |
browser.snapshot(mode="interactive", limit=30, max_chars=12000) | Capture a bounded interactive snapshot. |
browser.query(selector=..., include_html=True, limit=20) | Query elements with bounded outerHTML. |
browser.query(cursor=next_cursor) | Continue the same captured observation. |
Open a page and obtain DOM elements
The executable portion reads links on example.com without clicking or submitting. The commented #name input recipe requires a page that actually contains that field. Responses are JSON observations, not live DOM objects supporting element.click(), or a complete unbounded HTML document. Dispatch actions through SDK click/fill methods. Fields can include ref, tag, role, name, attributes, text, bounds, states, and frameId, depending on the installed server and observation mode. Exiting with launch() preserves the window.
from kingai_browser import launch
with launch() as browser:
browser.new_tab("https://example.com")
browser.wait(selector="body", state="visible", timeout_ms=15000)
# Read a compact DOM/accessibility observation with actionable refs.
snapshot = browser.snapshot(mode="interactive", limit=30)
print(snapshot.get("text", ""))
# Query actual DOM elements and request bounded outerHTML when needed.
result = browser.query(selector="a", include_html=True, limit=20)
for element in result.get("elements", []):
print(element.get("ref"), element.get("tag"), element.get("name"))
print(element.get("attributes", {}))
# On a page containing your own form, query the exact intended input:
# found = browser.query(selector="#name", limit=2)["elements"]
# if len(found) != 1:
# raise RuntimeError("Expected exactly one input")
# browser.fill(ref=found[0]["ref"], text="KingAI", humanize=False)Where interactive_elements comes from
interactive_elements belongs to the optional BrowserAutomation facade. Python capture_state() assembles it during observation; it is not stored in the browser or profile database. The fragment below only explains assignment; real state also contains url, title, session_id, tabs, page_content, and help. The value is a JSON string of the entire bounded snapshot response, not an element list. The facade currently requests the default compact snapshot, so the historical field name does not imply interactive-only content.
snapshot = browser.snapshot(max_chars=20000)
state = {"interactive_elements": json.dumps(snapshot, ensure_ascii=False)}Parse the string before reading elements
Parse with json.loads(), then read the elements array and inspect text and truncated. Do not iterate the interactive_elements string itself. If launch()/KingAI already opened the page, keep using that session instead of starting the default profile again. A new facade should explicitly attach an authorized active session_id. Refresh refs after navigation or DOM replacement. Continue pagination using only the returned cursor, without resending filters.
import json
from kingai_browser import BrowserAutomation
with BrowserAutomation() as agent_browser:
agent_browser.execute("go_to_url", url="https://example.com")
browser_state = agent_browser.get_current_state()
snapshot = json.loads(browser_state["interactive_elements"])
for element in snapshot.get("elements", []):
print(element.get("ref"), element.get("tag"), element.get("name"))
print(snapshot.get("text", ""))
print("Snapshot truncated:", snapshot.get("truncated", False))Snapshot budgets and query pagination
Python
page = browser.read() # readable page content
snapshot = browser.snapshot(mode="interactive", limit=30, max_chars=12000)
query = browser.query(selector="input, textarea, button", include_html=True, limit=20)
elements = query["elements"] # bounded DOM summaries, not live DOM objects
for element in elements:
print(element.get("ref"), element.get("tag"), element.get("name"))
# Follow the SAME captured observation without resending filters:
if query.get("nextCursor"):
next_page = browser.query(cursor=query["nextCursor"])06 · Waiting, clicking, typing, and scrolling
Use either selector or ref, not both. Replace the form selectors with real elements from your target page. fill replaces content; type appends. Basic recipes explicitly set humanize=False; enabling humanization requires a valid entitlement. Dispatch is not business success: observe the result. Java and Go input convenience methods also accept options.
| Function / call | Purpose |
|---|---|
browser.wait(selector=..., state="visible", timeout_ms=15000) | Wait for a page condition. |
browser.fill(ref=..., text=..., humanize=False) | Replace input text. |
browser.type(ref=..., text=..., humanize=False) | Append text. |
browser.click(selector, humanize=False) | Click an element. |
browser.key("Tab", humanize=False) | Send a key. |
browser.hover(selector, humanize=False) | Hover over an element. |
browser.scroll(300, humanize=False) | Scroll the page. |
Python
browser.wait(selector="#name", state="visible", timeout_ms=15000)
found = browser.query(selector="#name", limit=2)
if len(found["elements"]) != 1:
raise RuntimeError("Expected exactly one name input")
name_ref = found["elements"][0]["ref"]
browser.fill(ref=name_ref, text="KingAI", humanize=False) # replace existing text
browser.type(ref=name_ref, text=" SDK", humanize=False) # append text
browser.key("Tab", humanize=False)
browser.hover("#submit", humanize=False)
browser.scroll(300, humanize=False)
browser.click("#submit", humanize=False)
browser.wait(selector='#result[data-submitted="true"]', timeout_ms=10000)
result_text = browser.evaluate("document.querySelector('#result').textContent")07 · JavaScript evaluation and bounded previews
evaluate retains raw evaluation semantics. evaluate_preview returns a bounded preview; truncated means partial output. A large evaluate result can return RESULT_TOO_LARGE after execution has already happened. Never rerun a side-effect expression just to retrieve output. Node.js/Java use evaluatePreview; Go uses EvaluatePreview.
| Function / call | Purpose |
|---|---|
browser.evaluate(expression) | Evaluate a JavaScript expression. |
browser.evaluate_preview(expression) | Return a bounded result preview. |
Python
title = browser.evaluate("document.title")
preview = browser.evaluate_preview("({title:document.title,text:document.body.innerText})")
if preview.get("truncated"):
print("Preview is partial; request selected fields or read-only pages of data")08 · Screenshots, PDF, and file transfer
Configure absolute file_roots, download_dir, and artifact_dir paths on the client. Uploads must stay inside permitted roots. Screenshot and PDF responses describe server-produced artifacts; do not assume a byte array. Upload and download recipes require actual file inputs or download links.
| Function / call | Purpose |
|---|---|
browser.screenshot() | Create a screenshot. |
browser.pdf() | Create a PDF. |
browser.upload(paths, selector=...) | Upload files through a real file input. |
browser.download(selector=...) | Download using a real download link. |
Python
# Configure absolute trusted paths when constructing the client:
# KingAI(file_roots=[r"D:\demo\uploads"],
# download_dir=r"D:\demo\downloads", artifact_dir=r"D:\demo\artifacts")
image = browser.screenshot()
document = browser.pdf()
# Target-page examples; the local form does not contain these elements:
# browser.upload([r"D:\demo\uploads\document.txt"], selector='input[type="file"]')
# browser.download(selector="#download-link")09 · Cookies and Storage
These methods read site state. Keep cookies and storage out of public logs. Read the installed tool schema before calling state-changing extensions; do not invent setter parameters.
| Function / call | Purpose |
|---|---|
browser.cookies() | Read cookies. |
browser.storage() | Read site storage. |
Python
cookies = browser.cookies()
storage = browser.storage()
# Do not print/export cookies or storage into public logs.10 · Saved Skill workflows
List Skills, inspect a real skill_id, then run it with its declared parameters. Obtain the runId from the returned start result. Parameters differ by Skill; Java/Go can use generic call / Call when a convenience method is unavailable.
| Function / call | Purpose |
|---|---|
api.skills() | List saved Skills. |
api.describe_skill(skill_id) | Inspect a Skill and its parameters. |
api.run_skill(profile_id, skill_id, **options) | Start replay with declared options. |
api.skill_status(run_id) | Read run status. |
api.cancel_skill(run_id) | Explicitly cancel a run. |
api.skill_runs() | List Skill runs. |
Python
skills = api.skills()
# Use a real skill_id from the list, then inspect required parameters:
# description = api.describe_skill(skill_id)
# started = api.run_skill(profile_id, skill_id, **options_from_description)
# status = api.skill_status(started["runId"])
# api.cancel_skill(started["runId"]) # only if you intend to cancel
runs = api.skill_runs()11 · The installed tool catalog
Convenience methods do not cover every installed capability. Inspect names, required fields, and descriptions for iframe, network, console, and other tools before a generic call. Run the following commands from the GitHub repository root after obtaining its example scripts; these are not commands shipped by the pip package.
Repository example commands
python python/examples/mcp_tool_catalog.py
python python/examples/mcp_tool_catalog.py --tool browser_query12 · Errors and execution results
KingAIError exposes a structured error code. Do not automatically replay a click or input with an unknown outcome. Use request_status only with a real Runtime request ID supplied by the backend; a JSON-RPC ID is not a substitute. PAGE_NOT_VISIBLE requires restoring and activating the page. Ownership, account limits, and leases still apply.
| Function / call | Purpose |
|---|---|
KingAIError.code | Read the error code without exposing sensitive details. |
Python
from kingai_browser import KingAIError
try:
page = browser.read()
except KingAIError as error:
print(error.code) # keep structured details private unless sanitized
raise # no automatic replay of a previous click/type