DEV Community

MilkyWay008
MilkyWay008

Posted on Originally published at github.com

Your browser agent keeps "fixing" filled forms: the HTML value trap

Your browser agent keeps "fixing" filled forms: the HTML value trap

If you run browser automation agents, you've probably watched one do something maddening: the page has a form that's already filled in, and the agent types over it anyway. Or it skips the field entirely. Or it clears a value you needed kept.

The page showed "John Doe" right there in the input. The agent's view of the page said empty. Who's wrong?

Neither of you, exactly. The agent is reading the wrong thing, and it's a bug that shipped in browser-use 0.13.7 and older, fixed in 0.13.9. Here's what was happening, why it's a general trap for anyone scraping or automating the web, and what to do about it.

The short version of the bug

HTML inputs have two different "values":

  • The value attribute: what's in the markup when the page loads. <input value="John Doe">
  • The value property: what's actually in the field right now, after JavaScript, autofill, a framework binding, or the browser's own session restore has touched it.

JavaScript sets the property, not the attribute. If a script fills a field, the attribute stays empty forever. That's normal, spec-correct behavior.

The bug: browser-use's DOM snapshot only serialized the static attribute. So any field filled by anything other than the initial markup looked empty to the model. The agent would then happily retype over existing data, skip required fields it thought were blank, or drop values the user had carefully entered. Intermittent too, which made it worse: same page, same field, sometimes visible, sometimes not. The kind of bug that makes you question your own sanity.

The project's regression test told the story: on the broken code, a script-filled field came back as None where the value "Ada Lovelace" should have been. AssertionError. That's the whole bug in one line.

What the fix does

The fix (PR #5650, merged, shipped in 0.13.9) reads the live values from Chrome's DOM snapshot instead of the markup: the inputValue, textValue, and inputChecked fields from DOMSnapshot.captureSnapshot, then overrides the serialized attributes with those.

A couple of deliberate choices in the fix worth knowing about:

  • Sensitive fields are excluded on purpose. Password, file, and hidden inputs, plus anything with autocomplete like credit card or one-time-code, do not get their live values into the snapshot. Good. You don't want card numbers and OTPs floating through an LLM's context or sitting in a debug log. If your agent needs to read those, do it with an explicit, scoped step, not via the general snapshot.
  • Live checked state now wins over the attribute too, same class of bug for checkboxes and radios.

What to do

If you're on browser-use 0.13.8 or older, upgrade. That's the whole fix:

pip install -U browser-use
Enter fullscreen mode Exit fullscreen mode

0.13.9 has it. Nothing to configure.

If you're pinned to an older version for some reason, the workaround is to stop trusting the serialized DOM and read the live property yourself: before acting on a field, evaluate el.value in the page for that element, then decide whether to skip, merge, or overwrite. It's a custom action, and it's clunky, but it works. (The exact registration API moved around between versions, so check the repo's examples for your release.)

The general lesson

This isn't a browser-use-only bug. It's the attribute-vs-property distinction, and it bites every scraper and automation tool that builds its world model from serialized DOM:

  • The value and checked attributes are initial hints from the markup.
  • The value and checked properties are current state.
  • JavaScript, autofill, and browser session restore write the property and never look back at the attribute.

Any tool that snapshots attributes and calls it "the page" will misread filled fields as empty. When you're building or debugging one, ask what it actually reads: serialized attributes, or live properties via something like CDP's DOMSnapshot (inputValue/textValue/inputChecked) or an in-page el.value evaluation.

And if you're the one writing the extraction layer, do the sensitive-field filtering at that layer, not in your prompt. The model should never even see a password field's contents, because "never" is a lot easier to guarantee at extraction time than it is in a conversation.

One more thing worth saying: this whole class of bug is why you should treat "the page looks empty to my agent" as a data problem before you treat it as a model problem. The model isn't hallucinating an empty form. It's being shown one.

Found this useful? The fix is upstream, so the best thing you can do is update and move on. If you're stuck on an old pin, the property-read workaround above will carry you. And if your agent is about to type over a field you care about, that's your cue to check which value it's reading.

Top comments (0)