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
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.