BADGER

Reliable Browser Automation ≠ One-Off Scripts

Playwright is fantastic until your quick automation task devolves into hundreds of lines of loops, retries, and messy conditionals.

We hit this exact wall building robust form-filling bots. Instead of adding more hacks, we asked: What if automation logic was data, not code?

The result is BADGER (Browser Automation Directed Graph Engine Ruleset) – a workflow DSL built around explicit, maintainable graphs of browser actions. You can find the full types on our Github.

Why Not Just Use Playwright Directly?

Playwright is powerful and intuitive—perfect for quick scripts. But when automations grow beyond simple use-cases, scripts quickly become:

  • Hard to maintain: Logic, retries, loops, and edge cases spiral into tangled, fragile code.

  • Painful to debug: Tracing errors through imperative scripts wastes valuable developer time.

  • Poorly reusable: Mixing logic directly with implementation details makes reusing code difficult.

BADGER was designed to solve for this.

Automation As Data, Not Code

BADGER addresses Playwright’s scalability problems by modeling automation as explicit graphs, turning browser actions and logic into structured data.

Each workflow becomes a directed graph composed of:

  • Nodes: Clearly defined browser actions (e.g., CLICK, INPUT_TEXT, BOOL_CONDITION), each with a single responsibility.

  • Edges: Explicit control flow connections that visually and programmatically represent conditions, loops, and execution paths.

BADGER addresses Playwright’s scalability problems by modeling automation as explicit graphs, turning browser actions and logic into structured data.

Each workflow becomes a directed graph composed of:

  • Nodes: Clearly defined browser actions (e.g., CLICK, INPUT_TEXT, BOOL_CONDITION), each with a single responsibility.

  • Edges: Explicit control flow connections that visually and programmatically represent conditions, loops, and execution paths.

Key Benefits

  • Easy Debugging: Pinpoint failures within individual nodes and graph paths.

  • Reusable Components: Build modular automation libraries with reusable nodes.

  • Visual Clarity: Graph structure makes complex workflows easy to understand and maintain.

One added benefit of the graph structure is that it's super easy to visualize. Here's an example for a browser agent that posts a comment on X.

Technical Deep Dive

BADGER offers a lot of fields to customize the behavior of your browser automations. When applicable, we're trying to set good defaults. Here's a deep dive on the most important ones.

Workflow Fields
  • use_native_actions: Enables OS-level actions such as clicking and typing via a desktop application integration. This is particularly useful when standard JavaScript methods encounter issues with complex or secured web elements.

  • input_schema: Defines the structure of input data provided by users or systems to the automation workflow. Commonly used for form-filling or dynamic content input, ensuring data provided meets website form validations.

  • output_schema: Specifies the structured data format returned by the browser agent after workflow execution. Essential for standardizing outputs for downstream processes.

Node Types

Each node represents a distinct browser action or logical step in the workflow:

Action Nodes

  • Navigate: Opens a specified URL.

    • url: Destination URL.

  • Click: Click on an element.

    • selector: DOM selector of the element to click. Used if execution is STATIC

    • prompt: The prompt for the LLM describing the element to interact with. Used if execution is LLM_DOM or LLM_VISION

    • execution: Determines interaction method (STATIC, LLM_DOM, LLM_VISION).

    • human_mode: When true, performs click actions using human-like mouse movements and speed patterns, mimicking natural user interactions.

  • InputText: Inputs text into fields.

    • text: Text to input.

    • do_not_clear: Prevents clearing existing text if true.

    • submit_after_input: Automatically submits form after input if true.

    • max_retries_with_reload: In case the element cannot be found, the amount of retries with in-between reloads of the page.

  • InputSelect: Chooses an option from a select field.

    • value: Desired selection value.

    • fuzzy_match: Enables approximate matching of selection options using LLMs.

  • ExtractDatamodel: Extracts structured data.

    • extract_data_model: JSON schema defining data structure.

  • Screenshot: Takes a screenshot of the page. Can be configured to be full-size by setting the max_scrolls parameter.

    • selector: Element selector to capture.

    • max_scrolls: Number of scroll actions.

Condition and Loop Nodes

  • BoolCondition: Handles logical branching.

    • comparison_operator: Type of comparison (EQUAL, NOT_EQUAL, CONTAINS, etc.).

    • comparison_value_1 and comparison_value_2: Values for logical comparison.

    • execution: Execution method (STATIC, LLM_DOM, LLM_VISION).

  • Loop: Executes repeated operations.

    • over: Number or array to iterate over.

    • variable_current_item: Current iteration's item.

    • variable_current_index: Current iteration's index.

Specialized Nodes

  • Tfa (Two-Factor Authentication): Handles entering of 2FA codes.

    • selector: DOM selector for input.

    • code: 2FA code value or retrieval method.

    • tfa_type: 2FA method (SMS, EMAIL, AUTHENTICATOR).

    • tfa_url: URL associated with 2FA validation.

  • FileUpload: Manages uploading files.

    • signed_file_url: Secure URL that points to the file.

  • FileDownload: Facilitates downloading files.

    • continue_on_failed_download: Continues workflow even if download fails.

    • metadata: Any metadata to be sent together with the file URL of the downloaded file.

  • TabManagement: Controls browser tabs.

    • tabAction: Action (OPEN, CLOSE, SWITCH).

    • url: URL for opening a tab.

    • tab_index: Tab index for switching tabs.

  • UserInteraction: Awaits manual user input or confirmation.

    • expected_datamodel: Data structure expected from user.

    • timeout: Maximum wait duration.

Edges

Edges define control flow:

  • true, false: Branching logic

  • loop_done, loop_not_done: Lop control

  • to: Sequential transitions

Execution Types

BADGER nodes can leverage different execution strategies:

  • STATIC: Uses explicit selectors, fully deterministic.

  • LLM_DOM: Uses the DOM to fulfill the action e.g. finding the next element to click on.

  • LLM_VISION: Uses the screenshot to fulfill the action.

Trade-Offs And Challenges

Building and maintaining a DSL has trade-offs:

  • Initial Complexity: A DSL requires upfront investment and design effort.

  • Performance Overhead: Abstraction may add minor performance cost, but this is negligible compared to the reliability benefits.

Why This Matters for Reliable Browser Agents

LLM-driven runtime prompting looks great in demos but fails in production. BADGER solves this by drawing a firm line between where LLMs help and where they don’t.


  • Deterministic at runtime: Workflows run as explicit, structured graphs. Predictable, debuggable, and fast.

  • LLMs for targeted repair: When things break, only specific DSL nodes are regenerated – keeping fixes local and understandable.


This approach lets you debug, version-control, and reliably scale browser automation workflows.

It combines LLM flexibility exactly where it’s needed, with predictable, maintainable execution everywhere else.

Check out this blog article describing our overall system.