Skip to main content
Veto integrates with browser-use to validate every browser action before execution. This provides guardrails for AI agents that automate web browsing.

Installation

npm install veto-sdk browser-use-node
browser-use has separate packages for TypeScript (browser-use-node) and Python (browser-use). Veto supports both.

Quick Start

TypeScript (browser-use-node)

import { Veto } from 'veto-sdk';
import { wrapBrowserUse } from 'veto-sdk/integrations/browser-use';
import { Agent, Browser } from 'browser-use-node';
import { openai } from '@ai-sdk/openai';

// Initialize Veto
const veto = await Veto.init();

// Create Veto-wrapped controller
const controller = await wrapBrowserUse(veto, {
  onDeny: (action, params, reason) => {
    console.error(`🛑 Blocked ${action}: ${reason}`);
  },
});

// Create browser-use agent with Veto controller
const agent = new Agent({
  task: "Search DuckDuckGo for 'best laptops 2025'",
  llm: openai('gpt-4o'),
  browser: new Browser(),
  controller, // Veto-wrapped controller
});

// Run agent - all browser actions validated through Veto
const result = await agent.run();
console.log(result);

Python (browser-use)

from veto import Veto, VetoOptions
from veto.integrations.browser_use import wrap_browser_use
from browser_use import Agent, BrowserSession
from langchain_google_genai import ChatGoogleGenerativeAI

# Initialize Veto
veto = await Veto.init(VetoOptions(api_key="your-key"))

# Create Veto-wrapped tools
tools = await wrap_browser_use(
    veto,
    on_deny=lambda action, params, reason: print(f"🛑 Blocked {action}: {reason}"),
)

# Create browser-use agent with Veto tools
agent = Agent(
    task="Search DuckDuckGo for 'best laptops 2025'",
    llm=ChatGoogleGenerativeAI(model="gemini-2.0-flash"),
    tools=tools,  # Veto-wrapped tools
    browser_session=BrowserSession(),
)

# Run agent - all browser actions validated through Veto
result = await agent.run()
print(result)

How It Works

TypeScript Implementation

wrapBrowserUse() returns a custom Controller subclass that intercepts the act() method:
  1. Agent decides to perform a browser action (click, navigate, input, etc.)
  2. Controller’s act() method intercepts the call
  3. Veto validates the action and parameters
  4. If allowed, original implementation executes
  5. If denied, returns ActionResult({ error: "Action blocked by Veto: ..." })

Python Implementation

wrap_browser_use() returns a custom Tools subclass that intercepts the act() method:
  1. Agent decides to perform a browser action
  2. Tools’ act() method intercepts the call
  3. Veto validates the action and parameters through Veto Cloud
  4. If allowed, original implementation executes
  5. If denied, returns ActionResult(error="Action blocked by Veto: ...")

Validated Actions

By default, Veto validates these browser actions: TypeScript (browser-use-node):
  • go_to_url
  • click_element
  • input_text
  • extract_page_content
  • scroll
  • done
  • tab
Python (browser-use):
  • navigate
  • search
  • click
  • input
  • extract
  • scroll
  • done

Configuration

Customize Validated Actions

You can specify which actions to validate:
const controller = await wrapBrowserUse(veto, {
  validatedActions: new Set(['go_to_url', 'click_element', 'input_text']),
  onAllow: (action, params) => {
    console.log(`✓ Allowed ${action}`);
  },
  onDeny: (action, params, reason) => {
    console.error(`✗ Denied ${action}: ${reason}`);
  },
});

Callbacks

Both implementations support callbacks:
  • onAllow / on_allow: Called when an action is allowed
  • onDeny / on_deny: Called when an action is denied
const controller = await wrapBrowserUse(veto, {
  onAllow: (action, params) => {
    logger.info('Browser action allowed', { action, params });
  },
  onDeny: (action, params, reason) => {
    logger.warn('Browser action denied', { action, params, reason });
    // Send alert, log to monitoring system, etc.
  },
});

Validation Rules

Configure rules for browser actions in your veto/rules/ directory:

Block Dangerous URLs

rules:
  - id: block-external-sites
    name: Block navigation to external sites
    action: block
    tools:
      - go_to_url
      - navigate
    conditions:
      - field: arguments.url
        operator: not_matches
        value: "^https://(www\\.)?company\\.com"
    severity: high

Limit Input Actions

rules:
  - id: prevent-sensitive-input
    name: Prevent input on sensitive fields
    action: block
    tools:
      - input_text
      - input
    llm:
      condition: "Does the element selector indicate a password, credit card, or SSN field?"
      severity: critical

Validate Click Targets

rules:
  - id: confirm-destructive-clicks
    name: Require approval for destructive clicks
    action: ask
    tools:
      - click_element
      - click
    llm:
      condition: "Does clicking this element perform a destructive action like delete, remove, or cancel?"
      severity: medium

Block Data Extraction

rules:
  - id: limit-data-extraction
    name: Limit data extraction scope
    action: block
    tools:
      - extract_page_content
      - extract
    conditions:
      - field: arguments.selector
        operator: matches
        value: "(password|ssn|credit)"

Complete Example

Here’s a complete example with rules and callbacks:
import { Veto } from 'veto-sdk';
import { wrapBrowserUse } from 'veto-sdk/integrations/browser-use';
import { Agent, Browser } from 'browser-use-node';
import { openai } from '@ai-sdk/openai';

// Initialize Veto
const veto = await Veto.init();

// Create wrapped controller with callbacks
const controller = await wrapBrowserUse(veto, {
  validatedActions: new Set([
    'go_to_url',
    'click_element',
    'input_text',
    'extract_page_content',
  ]),
  onAllow: (action, params) => {
    console.log(`✓ ${action}:`, JSON.stringify(params, null, 2));
  },
  onDeny: (action, params, reason) => {
    console.error(`✗ ${action} BLOCKED:`);
    console.error(`  Reason: ${reason}`);
    console.error(`  Params:`, JSON.stringify(params, null, 2));
  },
});

// Create browser automation agent
const agent = new Agent({
  task: `
    Go to example.com
    Click the "Sign In" button
    Enter username: [email protected]
    Do NOT enter a password
  `,
  llm: openai('gpt-4o'),
  browser: new Browser({ headless: false }),
  controller,
});

// Run with error handling
try {
  const result = await agent.run();
  console.log('Agent completed:', result);
} catch (error) {
  console.error('Agent failed:', error);
}

Tool Schema Registration

Both implementations automatically register browser action schemas with Veto Cloud (if enabled):
  • TypeScript: Extracts action schemas from the controller’s registry
  • Python: Extracts action schemas from the tools’ registry
This allows you to configure policies via the Veto Cloud dashboard without modifying code.

TypeScript API Reference

wrapBrowserUse(veto, options?)

Create a browser-use-node Controller with Veto validation. Parameters:
  • veto: Veto - Initialized Veto instance
  • options?: WrapBrowserUseOptions
    • validatedActions?: Set<string> - Actions to validate (default: all standard actions)
    • onAllow?: (actionName: string, params: Record<string, unknown>) => void | Promise<void>
    • onDeny?: (actionName: string, params: Record<string, unknown>, reason: string) => void | Promise<void>
Returns: Promise<Controller> - Drop-in replacement for browser-use-node Controller Default validated actions:
const DEFAULT_VALIDATED_ACTIONS = new Set([
  'go_to_url',
  'click_element',
  'input_text',
  'extract_page_content',
  'scroll',
  'done',
  'tab',
]);

Python API Reference

wrap_browser_use(veto, *, validated_actions, on_allow, on_deny)

Create a browser-use Tools instance with Veto validation. Parameters:
  • veto: Veto - Initialized Veto instance
  • validated_actions: set[str] | None - Actions to validate (default: all standard actions)
  • on_allow: Callable | None - Callback for allowed actions
  • on_deny: Callable | None - Callback for denied actions
Returns: Tools - Drop-in replacement for browser-use Tools Default validated actions:
DEFAULT_VALIDATED_ACTIONS = {
    "navigate",
    "search",
    "click",
    "input",
    "extract",
    "scroll",
    "done",
}

Security Best Practices

  1. Always validate navigation: Block access to unauthorized domains
  2. Limit input actions: Prevent input on sensitive fields (passwords, payment info)
  3. Validate extraction: Ensure agents don’t extract PII or sensitive data
  4. Use LLM rules: For semantic validation (e.g., “is this action destructive?”)
  5. Enable callbacks: Log all browser actions for audit trails
  6. Test in headless: false: Watch the browser during development to verify guardrails

Next Steps

Configure Rules

Define validation rules for browser actions

Browser Safety

Best practices for securing browser automation

Veto Cloud

Use Veto Cloud for centralized policy management

API Reference

Full Veto API documentation

Build docs developers (and LLMs) love