Skip to main content

Browser agent (Python)

Availability

Open core · self-host + all Splyntra Cloud plans. The security and governance calls used here (guard, authorize, log_action) run against your Splyntra backend — self-hosted or Cloud.

Autonomous browser agents navigate real websites, click, type into forms, and extract untrusted DOM content — which introduces risks a chat agent never faces: indirect prompt injections hidden on third-party pages, credentials typed into untrusted forms, and agents wandering onto unapproved domains. This guide follows the runnable examples/browser-use-agent example, which wires Browser Use to Splyntra for observability and inline security governance.

The example ships two implementations:

  • python/agent.py — the primary example. Uses Browser Use auto-instrumentation for live runs, plus a high-fidelity simulation mode that emits the same span tree with no browser or API key required.
  • typescript/agent.ts — the same governance patterns for a browser-style agent built with manual wrapAgent / wrapTool / wrapLLM. It uses manual wrapping to keep the demo self-contained; to auto-instrument the TypeScript browser-use package instead, see Framework integrations.

Initialize telemetry first

Construct the Splyntra tracer before importing or running Browser Use — the adapter patches Agent/Controller at construction time, so ordering matters. Turn on both the browser-use adapter and your LLM provider so the agent's vision/reasoning calls are captured as llm_call spans:

from splyntra import Splyntra

splyntra = Splyntra(
api_key=os.environ["SPLYNTRA_API_KEY"],
project="browser-use-agent",
framework="browser-use",
instrument=("browser-use", "openai"),
guard="monitor", # or "block" to intercept inline
guard_fail_open=True, # never let a guard outage stall the agent
redact_by_default=True, # strip secrets from spans before export
)

With the adapter on, Agent.run() becomes the root agent span, each Agent.step() a step span, and every browser action (navigate, click, type, extract, …) a tool_call span nested underneath — no per-action decorators needed.

URL governance before navigation

Gate navigation on a policy check so an autonomous agent can't reach unapproved domains, internal subnets, or phishing endpoints. The example calls authorize from its navigate tool and refuses the request on a deny decision:

decision = authorize(
action="browser.navigate",
agent_id="browser_agent",
resource=domain,
context={"url": url, "domain": domain},
).get("decision", "allow")

if decision == "deny":
raise PermissionError(f"Blocked navigation to unauthorized domain: {domain}")

The check is synchronous and pre-navigation, so a blocked URL is never fetched. See Policies.

Indirect prompt-injection defense

Web pages are untrusted input. Before extracted DOM content reaches the LLM, run it through the guardrail so a jailbreak hidden in third-party HTML is caught before ingestion:

from splyntra.guard import enforce as guard_enforce

inspected = guard_enforce(raw_page_content, direction="input")

In block mode the guardrail raises SplyntraBlocked and the action is stopped; in monitor mode the detection is recorded on the span without interrupting the run. See Guardrails and Detection & redaction.

Immutable audit ledger

Record a tamper-evident audit entry for the completed session — every navigated URL, extracted dataset, and the run outcome — so browsing activity is provable after the fact:

log_action(
action="browser.workflow_completed",
actor="browser_agent",
resource=dest_url,
metadata={"task": task, "url": dest_url, "provider": provider},
)

See Audit ledger.

Run it

From examples/browser-use-agent/python:

pip install -r requirements.txt
cp .env.example .env

# Instant offline simulation — full span tree, no API key or browser needed:
python agent.py --mock

# URL governance: attempt an unauthorized/phishing domain and watch it get blocked:
python agent.py --mock --demo-url-block

# Injection defense: a page carrying a hidden jailbreak, blocked inline:
python agent.py --mock --demo-web-injection --guard block

# Live run against a real browser (requires Browser Use + Playwright):
# pip install browser-use playwright && playwright install chromium
python agent.py --provider groq

The TypeScript variant runs the same demos from examples/browser-use-agent/typescript via npx tsx agent.ts --mock.

What you get

Open Traces to see the browser action waterfall: the browser_agent root, its step spans, and a tool_call per navigate/click/type/ extract with millisecond latency. Vision/reasoning calls appear as llm_call spans with token usage and cost. Guardrail detections and redactions show on the Security screen, and each session's audit entry lands in the ledger.

Next steps