Updated 2026-02-14 — Python-only plugin for adding deterministic verification to Browser Use agents.
browser-use is great at planning + acting. Predicate adds a deterministic verification layer so your run can fail fast when outcomes aren’t provably correct (drift / hallucination).
This page documents the Browser Use deterministic verification plugin shipped inside the Predicate Python SDK (predicate-sdk).
Browser Use agents are especially prone to scroll no-op drift (the agent “scrolls”, but the UI doesn’t move). Use /docs/sdk/verifications for scroll verification and expanded .eventually() reliability knobs (adaptive resnapshotting).
See the runnable demo in the SDK playground: predicate-sdk-playground/browser-use-debugging.
For scroll verification and expanded .eventually() reliability knobs, see Verifications.
pip install "predicate-sdk[browser-use]"Environment variables (typical):
PREDICATE_API_KEY — optional for local-only usage; required for Gateway snapshots and/or trace uploadBROWSER_USE_API_KEY — if your Browser Use LLM provider needs itagent.run() (recommended)Pass the plugin’s step hooks into Browser Use’s agent.run(...).
import os
from browser_use import Agent, ChatBrowserUse
from predicate.integrations.browser_use import (
PredicateBrowserUsePlugin,
PredicateBrowserUsePluginConfig,
)
plugin = PredicateBrowserUsePlugin(
config=PredicateBrowserUsePluginConfig(
predicate_api_key=os.getenv("PREDICATE_API_KEY"),
use_api=True, # optional; set False to force local-only snapshots
auto_snapshot_each_step=True,
auto_checks_each_step=False, # start manual, then add auto checks later
# tracer is optional (see below)
)
)
agent = Agent(task="Your task...", llm=ChatBrowserUse())
history = await agent.run(
on_step_start=plugin.on_step_start,
on_step_end=plugin.on_step_end,
max_steps=30,
)agent.step() loops (manual wrap)Browser Use’s built-in hooks are wired into agent.run(...). If you drive an agent step-by-step with agent.step(), wrap each step yourself.
await plugin.on_step_start(agent)
await agent.step()
await plugin.on_step_end(agent)await plugin.wrap_step(agent, agent.step())
# or (callable form)
await plugin.wrap_step(agent, agent.step)If you omit a tracer, the plugin still works (lowest friction), but you won’t get JSONL trace files / Studio timelines.
See Tracing & Debugging for sinks, upload, and event schemas.
traces/<run_id>.jsonl)import os
from predicate.tracer_factory import create_tracer
from predicate.integrations.browser_use import PredicateBrowserUsePlugin, PredicateBrowserUsePluginConfig
tracer = create_tracer(
run_id="browser-use-demo",
api_key=os.getenv("PREDICATE_API_KEY"), # optional; used for snapshot API, not required for local traces
upload_trace=False,
goal="Browser Use agent run (local trace)",
)
plugin = PredicateBrowserUsePlugin(
config=PredicateBrowserUsePluginConfig(
predicate_api_key=os.getenv("PREDICATE_API_KEY"),
tracer=tracer,
)
)import os
from predicate.tracer_factory import create_tracer
from predicate.integrations.browser_use import PredicateBrowserUsePlugin, PredicateBrowserUsePluginConfig
tracer = create_tracer(
api_key=os.getenv("PREDICATE_API_KEY"),
upload_trace=True,
goal="Browser Use agent run (cloud trace)",
)
plugin = PredicateBrowserUsePlugin(
config=PredicateBrowserUsePluginConfig(
predicate_api_key=os.getenv("PREDICATE_API_KEY"),
tracer=tracer,
)
)