Automation & SDK
Drive an Orbe profile from your own code — or from an AI assistant — through an internal control channel inside the Chromium core. Clicks, keys and scrolling travel the same event path as a real user's, and pages are read on the browser side rather than by running scripts in them.
Because there is no automation layer bolted on top, the page sees:
- no
navigator.webdriver, - no CDP (Chrome DevTools Protocol) session,
- no open debug port,
- no injected script and no isolated world.
What makes it different
The usual way to drive a browser for automation is over CDP, replaying instant, mechanical input. Orbe takes a different route by owning the browser engine underneath: input is delivered through the real event path, and the page is read on the browser side.
No automation trace
The signals a page can read to tell automation from a person — navigator.webdriver, the --enable-automation flag, a CDP session — are simply not present, because Orbe never turns them on. A clean fingerprint stays clean while you script it.
Human, per-profile behaviour
Movement and typing are humanized from each profile's own seed: curved mouse paths, think-pauses, typing rhythm, scroll inertia. The same profile behaves like the same person every day; different profiles behave like different people.
Discipline, on by default
Every command passes through a proxy check before opening, account-safety pacing, and a checkpoint detector that stops instead of pushing on — and a one-time warning when a profile works outside its usual hours.
One behaviour engine
Python, the line protocol for other languages and the MCP server all share a single humanization engine, so behaviour never drifts between clients; nothing is re-implemented.
Quickstart
The SDK is a small Python package that comes with the installer. You need Python 3.9 or newer on the Windows machine that runs Orbe. Install the package once from your Orbe folder (PowerShell):
python -m pip install --force-reinstall (Get-ChildItem "$env:LOCALAPPDATA\Programs\Orbe\app\current\sdk\orbe-*.whl").FullName
The package uses only the standard library and finds Orbe on its own. If you installed Orbe in a different folder, use that folder in place of %LOCALAPPDATA%\Programs\Orbe in the command, and set ORBE_EXE to the full path of Orbe.exe in its app\current. After an Orbe update, run the same command again to pick up the new package.
Then import it as orbe:
import orbe
# Opens the profile, connects the channel and checks the proxy —
# all on enter. Closes cleanly on exit.
with orbe.Trinh("my-profile") as t:
t.goto("https://example.com/login")
t.wait_for("Sign in") # wait until the text appears
t.click("Sign in") # click the element carrying that text
t.type("my-username", enter=True) # type with human timing, then Enter
t.scroll(600) # one human scroll gesture, downward
print(t.read()[:200]) # read the visible page text
t.screenshot("after-login.png") # capture through the compositor
with … as t:). Entering opens the browser and runs the safety checks; leaving closes the browser and the channel, even if your code raises.Prefer to run from an AI assistant such as Claude instead of writing code? Jump to MCP.
The Trinh session Python
orbe.Trinh is the public SDK session. It is safe by default: the proxy check and the checkpoint stop are always on, with no switch to turn them off — that is deliberate, because the first thing an undisciplined run costs you is an account. Only account-safety pacing can be turned off, per session.
orbe.Trinh(profile_id, *, headless=False, timeout=30.0,
platform=None, pacing="on", on_rest=None, rotate=None, open_on_rotate_fail=False)
The only required argument is the profile id; the rest are keyword-only options:
False.30.0."on"; "off" removes the human-like rests (see the warning under pacing).True gets a new IP before the browser starts, False skips it for this open, None (default) follows the profile's Rotate IP on open setting. Ignored for your own proxy or no proxy.False.orbe package's stable, official surface. An option that your installed version does not support raises orbe.NotSupported; every SDK error is an orbe.OrbeError.Lifecycle
Open the browser for the profile and connect the control channel. Called automatically by with orbe.Trinh(...) as t:. Runs the proxy check on open — if the proxy is dead, in the wrong country or incompletely set up, it raises before a browser window is shown.
Close the browser and the channel. Called automatically on leaving the with block. Safe to call more than once.
Navigate & wait
Navigate the current tab to url. Returns the tab id; later commands target this tab.
A plain pause — a "reading" or "thinking" gap. Use between steps as a real user would.
Wait until an element carrying text appears (substring, case-insensitive). Returns True if seen within timeout, else False. Polls through the channel — no script runs in the page. Do not act on a page before you have waited for something distinctive on it.
Read the page
Return all visible text on the page, read on the browser side (C++ renderer). Use it to learn what is on the page and to confirm an action worked.
List actionable elements (buttons, links, inputs) as {type, text, link, x, y, w, h} — the element's kind, its text, its link, and its viewport box. Use it to find precise coordinates when clicking by text is not enough.
Act like a person
Click the element carrying text (substring, case-insensitive; picks the smallest matching box, so you hit the real control, not its container). The mouse moves there with human timing. Returns False if no such element exists yet — in that case wait_for or read again rather than guessing coordinates.
Click a viewport coordinate, for when you already know the point (for example from elements() or a screenshot).
Type text with human rhythm into the focused element — click the field first. enter=True presses Enter after the last character.
Scroll one real human gesture from point (x, y). dy only chooses the direction (negative = up); the distance is one human gesture, not an exact pixel amount. After scrolling, read or screenshot to see where it landed.
Scroll down with human gestures, repeating until the page shows text or the bottom is reached (the page text stops changing). Returns True if found. This is the right way to "scroll to X" — do not guess pixel amounts.
Screenshot
Capture the visible viewport through the compositor. The image is a lossless PNG of the page as it really renders — it carries no canvas noise (canvas is noised per-profile, but a screenshot is the true render), so it is reliable for verifying and debugging. Returns the PNG bytes; if path is given, also writes the file.
Safe by default
The public SDK wraps every command in a discipline layer. You do not opt in, and the proxy check and the checkpoint stop below cannot be switched off; pacing is on by default and can be turned off per session.
- Out-of-hours warning. Automation is never stopped because of the time of day. When a profile works outside its usual hours — 7:00–23:00 by default in the proxy's timezone (without a proxy, your own IP's timezone, or the profile's country if that can't be looked up); with a platform hint, TikTok 8:00–24:00, YouTube and Google 6:00–24:00, Twitter 7:00–24:00, Facebook, Instagram and Shopee 7:00–23:00 — Orbe warns once per session and carries on, for example: "Outside usual active hours 7:00–23:00 (Asia/Ho_Chi_Minh); it is now 23:00. Automation continues — accounts active at unusual hours are more likely to be reviewed." The SDK prints it to stderr as
[orbe] warning: …, the MCP server sends it as a warning notification, and the Workflow Editor shows it as a ! line in the run results. The warning appears only while pacing is on. - Third-party proxy limit. A profile outside the 20-profile limit opens without its proxy; look for the
proxy_disabledflag in the Local API and MCP profile list, open result and batch or schedule result rows. - Proxy check before opening. If the profile has a proxy and it is unreachable, in the wrong country or incompletely set up, Orbe does not open — a run on the wrong IP is more expensive than a run that never started. A profile with no proxy opens directly on your own IP.
- Checkpoint / captcha detection. After each state-changing step, Orbe reads the page (waiting for it to settle) and, if it sees a checkpoint or challenge — in the text or the URL — it stops, captures a screenshot, and reports it. Orbe never tries to solve or bypass a checkpoint.
Account-safety pacing
Orbe automation pauses like a person: about 1 in 8 actions (click, type, scroll, navigate) is followed by a 3–20 s rest. A tool call may take longer than the mouse movement itself; this is intentional, not a hang.
While it rests, the MCP server sends a progress message resting N s (account-safety pacing); the SDK prints that line to stderr, or calls your on_rest(seconds) callback in Python.
Pacing is on by default. You can turn it off for a session or a workflow:
- Python —
orbe.Trinh(profile_id, pacing="off"); - other languages —
orbe-sdk.cmd <profile-id> --pacing off; - MCP —
openwith"pacing": "off"; - Workflow Editor — the Pacing: On button next to Run, saved per workflow; turning it off asks you to confirm.
Handling a block
When discipline stops a command, the SDK raises a discipline error and the MCP tool returns BLOCKED (…) — carrying an English message and, for a checkpoint, the matched phrase, the URL and a screenshot. Catch it and handle it; do not retry blindly. Each row below is a distinct block condition:
| Class | What happened | What to do |
|---|---|---|
orbe.Checkpoint | A checkpoint or challenge was detected on the page or in the URL. Carries the matched phrase, the URL and a screenshot. | Stop this profile. Review by hand. Do not automate through it. |
orbe.ProxyError | The profile's proxy is unreachable, in the wrong country, or its settings are incomplete. | Fix the proxy before opening. |
orbe.PageUnreadable | The page could not be read after retrying — treated as unsafe, not "clean". | Let it stop; check connectivity and the page. |
orbe.BehaviorDataMissing | The human-behaviour library is missing, so movement would be synthetic (and detectable). | Reinstall or repair Orbe so the behaviour data is present. |
orbe.LicenseDisabled | The account's license is not valid for this action. | Sign in again and check your key in the dashboard. |
orbe.LedgerError | The usage counter file is corrupt — the SDK fails closed rather than guessing. | Investigate before forcing more actions. |
import orbe
try:
with orbe.Trinh("my-profile") as t:
t.goto("https://example.com")
t.click("Post")
except orbe.Blocked as e:
# A block. str(e) is an English message describing the condition;
# a checkpoint block also carries the matched phrase, URL and screenshot.
notify_me(str(e)) # a human should look at this profile
# do NOT retry the same action in a loop
orbe.Blocked, so except orbe.Blocked catches them all; catch a specific class from the table above when you want to handle one condition differently. str(e) is an English message, and a checkpoint block also carries the matched phrase, the URL and a screenshot.orbe.RateLimited and orbe.OutsideHours still exist so older code that catches them keeps working, but Orbe no longer raises them: there are no action caps, and nothing is blocked because of the time of day.
When a new IP can't be obtained
With rotate on (or the profile's Rotate IP on open ticked), a failed rotation raises orbe.RotateFailed and the browser does not open. It is not a discipline block — it subclasses orbe.OrbeError, not orbe.Blocked. It carries .reason and .retry_after:
reason | Meaning | What to do |
|---|---|---|
cooldown | The port changed IP less than 3 minutes ago. .retry_after is the number of seconds to wait. | Wait retry_after seconds, or open with rotate=False. |
timeout | No new IP after 60 s — the proxy may still be changing. | Try again shortly. |
api | The proxy provider didn't change the IP. | Try again; if it persists, check the port with your provider. |
no_token | No proxy token is set, so the port can't be rotated. | Add the token in Settings. |
.retry_after is a whole number of seconds when reason is cooldown, otherwise None. Pass open_on_rotate_fail=True to open on the current IP instead.
Other languages Any language
Any language can drive the same session over a small line protocol. The installer adds the bridge orbe-sdk.cmd to your Orbe folder; start it as a subprocess with the profile id and exchange one JSON object per line on stdin/stdout (started with only the profile id and no input, it does nothing). A quick test from Command Prompt: (echo {"cmd":"open"}& echo {"cmd":"close"}) | "%LOCALAPPDATA%\Programs\Orbe\orbe-sdk.cmd" <profile-id>. If you installed Orbe elsewhere, use that folder instead.
"%LOCALAPPDATA%\Programs\Orbe\orbe-sdk.cmd" <profile-id> [--rotate on|off] [--open-on-rotate-fail]
→ {"cmd":"open","url":"https://example.com"} ← {"ok":true,"result":null}
→ {"cmd":"goto","url":"https://example.com"} ← {"ok":true,"result":"<tab_id>"}
→ {"cmd":"wait_for","text":"Sign in"} ← {"ok":true,"result":true}
→ {"cmd":"click","text":"Sign in"} ← {"ok":true,"result":true}
→ {"cmd":"screenshot"} ← {"ok":true,"result":{"png_b64":"…"}}
→ {"cmd":"close"} ← {"ok":true,"result":null}
Commands are the same set as the SDK: open · goto · wait · wait_for · click · click_xy · type · scroll · scroll_until · read · elements · screenshot · close. A failed command returns {"ok":false,"error":"…"} and never crashes the bridge. --rotate on|off and --open-on-rotate-fail go on the command line after the profile id (not in the open command); a failed rotation returns {"ok":false,"code":"RotateFailed","error":"…","reason":"…","retry_after":…}. stdout carries the JSON protocol only; diagnostics go to stderr. Read results line by line and match them to the order you sent.
Local API for your own tools
Orbe also runs a Local API that your own scripts and tools can call — on this computer only (127.0.0.1), never on your network. It is on by default, on a random port chosen when Orbe installs. Manage it in Settings → Local API (the Local API item in the sidebar opens it):
- Enable Local API for external tools — turn it off if you don't use external tools;
- Port and Apply — change the port;
- Copy URL — the address,
http://127.0.0.1:<port>/orbe/v1; - Copy key — every request must send this key in the
X-Orbe-Keyheader; a missing or wrong key gets401. Treat the key like a password — anyone with it can control your profiles.
The Local API drives profiles through the same internal channel as the SDK — no CDP and no debug port; a request for CDP is refused with an error.
MCP — use Orbe from an AI assistant MCP
Orbe ships an MCP server that exposes the same actions as tools, so an assistant such as Claude Code, Cursor or Codex can act inside a profile in natural language. It is traceless like the SDK: no CDP, no in-page script, no debug port.
Install
On the machine that has Orbe (Windows), in Command Prompt. The MCP server is built into Orbe.exe, so there is nothing else to install:
claude mcp add orbe -- "%LOCALAPPDATA%\Programs\Orbe\app\current\Orbe.exe" --mcp
If you installed Orbe in a different folder, use the Orbe.exe in that folder's app\current — it keeps pointing at the current version after updates. You drive the server through the orbe tools, not by name.
Tools
| Tool | What it does |
|---|---|
open | Open a profile (profile, optional headless, url) — call this first. Optional rotate (boolean; blank follows the profile's Rotate IP on open) and open_on_rotate_fail (boolean, default false). A failed rotation returns isError with rotate_failed (<reason>): … and structured reason / retry_after. |
goto | Navigate the current tab to url. |
wait | Wait until the page shows text (returns found), or wait seconds. |
read | Read all visible text on the page. |
elements | List actionable elements with their text and box. |
click | Click the element carrying text, or coordinates x,y. |
type | Type text into the focused element; enter: true to submit. |
scroll | Scroll one human gesture in the direction of dy. |
scroll_until | Scroll down until text appears or the bottom is reached. |
screenshot | Capture the page, returns a PNG. |
close | Close the profile. |
list_blocks | List the workflow blocks Orbe supports and their fields — read before drafting a workflow. Data only; no profile needed. |
submit_flow | Submit a workflow (built from list_blocks steps) into Orbe as a draft — validated and saved, never run; the user reviews and runs it in the Workflow Editor. Data only. |
The last two tools let an assistant build a workflow for the user rather than drive the browser directly: it reads list_blocks, writes the flow, and submit_flow drops it into the Workflow Editor as a draft to review — it never auto-runs. See Build with AI.
Several profiles can be open at once; any tool with profile left blank targets the most recently opened one.
How an assistant should work
open→goto→waitfor a distinctive piece of text before acting.readto learn the page;screenshotwhen layout or images matter.- Click by the text on the element — the most reliable way. For an icon with no text, read coordinates from a screenshot and click
x,y. - To type into a field:
clickit first, thentype. - To reach something below the fold, use
scroll_until, not repeatedscrollguesses. - After each important action,
readorwaitto confirm the page changed — do not assume success. closewhen done.
BLOCKED (<code>): <reason> with isError and structured details (including the checkpoint phrase, URL and screenshot). The assistant must handle it — stop, report, or wait — not click on regardless.Rules for the assistant
- Do not mix other automation tools into an Orbe profile — Playwright, Puppeteer, Selenium or anything that attaches over CDP. Attaching once leaves exactly the trace Orbe exists to avoid.
- Move like a person. Timing is already humanized; your part is not to fire dozens of actions back to back without reading the page.
- Do not enter a password or secret the user has not given you in this session.
Recipes
Complete, runnable versions of these are on this site under examples/ — login_then_post.py, fill_form.py, scrape_list.py and fleet_multi_profile.py (many profiles at once) — each using only orbe and the standard library, with credentials read from the environment. The snippets below show the shape.
Log in, then confirm
import orbe
with orbe.Trinh("my-profile") as t:
t.goto("https://example.com/login")
t.wait_for("Password")
t.click("Email")
t.type("me@example.com")
t.click("Password")
t.type("...", enter=True)
if t.wait_for("Your feed", timeout=20):
print("logged in")
else:
t.screenshot("login-stuck.png") # something to look at by hand
Reach something below the fold
with orbe.Trinh("my-profile") as t:
t.goto("https://example.com/long-page")
if t.scroll_until("Load more"):
t.click("Load more")
Click a precise element with elements()
with orbe.Trinh("my-profile") as t:
t.goto("https://example.com")
for el in t.elements():
if el["type"] == "button" and "Follow" in (el["text"] or ""):
t.click_xy(el["x"] + el["w"] // 2, el["y"] + el["h"] // 2)
break
What Orbe does not do
Automation removes the automation trace; it does not change how a platform judges an account. Orbe gives every account a consistent, real-looking machine, its own IP, and human input — but how you nurture the account is still your part. Any tool that promises bans will never happen is not being honest with you.
See also Get started and Proxy.