Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why is cleaned text missing from FormData when the field still has a value?

Our disabled input retains its value but is absent from FormData. The ordinary and readonly inputs are included, even when empty. Cleanup changes the string; it does not decide which form controls become entries.

Tested October 25, 2026 · v24.22.1 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked field

Measured inputs and outputs

These are locally constructed test strings, not evidence that Claude inserts these characters. We executed the saved homepage script snapshot with a minimal DOM harness and compared exact strings. The invisible-checkbox state and dash mode appear in each row. The observations below test this page's specific question. Destination observations were measured separately in Chromium 156 using detached native controls and programmatic value assignment. Node reruns the actual homepage callback and reads the saved browser observations; it does not independently rerun the browser. No form was submitted. We make no detector-score or statistical-watermark removal claim.

Before and after observations; full code points and strings are in the JSON download.
Fixture and modeInput string and code pointsOutput and cleaner statusObserved before / after
Marked field
direct string / keep / invisible true
"A​B"
U+0041 U+200B U+0042
"AB"
Removed 1 invisible character
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"A​B"},{"disabled":true,"name":"disabled","readOnly":false,"value":"A​B"},{"disabled":false,"name":"readonly","readOnly":true,"value":"A​B"}],"entries":[["normal","A​B"],["readonly","A​B"]]}
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"AB"},{"disabled":true,"name":"disabled","readOnly":false,"value":"AB"},{"disabled":false,"name":"readonly","readOnly":true,"value":"AB"}],"entries":[["normal","AB"],["readonly","AB"]]}
Plain field
direct string / keep / invisible true
"AB"
U+0041 U+0042
"AB"
No selected invisible characters found
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"AB"},{"disabled":true,"name":"disabled","readOnly":false,"value":"AB"},{"disabled":false,"name":"readonly","readOnly":true,"value":"AB"}],"entries":[["normal","AB"],["readonly","AB"]]}
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"AB"},{"disabled":true,"name":"disabled","readOnly":false,"value":"AB"},{"disabled":false,"name":"readonly","readOnly":true,"value":"AB"}],"entries":[["normal","AB"],["readonly","AB"]]}
Empty field
direct string / keep / invisible true
""
""
No selected invisible characters found
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":""},{"disabled":true,"name":"disabled","readOnly":false,"value":""},{"disabled":false,"name":"readonly","readOnly":true,"value":""}],"entries":[["normal",""],["readonly",""]]}
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":""},{"disabled":true,"name":"disabled","readOnly":false,"value":""},{"disabled":false,"name":"readonly","readOnly":true,"value":""}],"entries":[["normal",""],["readonly",""]]}
Retained joiner
direct string / keep / invisible true
"A‍B"
U+0041 U+200D U+0042
"A‍B"
No selected invisible characters found
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"A‍B"},{"disabled":true,"name":"disabled","readOnly":false,"value":"A‍B"},{"disabled":false,"name":"readonly","readOnly":true,"value":"A‍B"}],"entries":[["normal","A‍B"],["readonly","A‍B"]]}
{"controls":[{"disabled":false,"name":"normal","readOnly":false,"value":"A‍B"},{"disabled":true,"name":"disabled","readOnly":false,"value":"A‍B"},{"disabled":false,"name":"readonly","readOnly":true,"value":"A‍B"}],"entries":[["normal","A‍B"],["readonly","A‍B"]]}

An existing value does not guarantee an entry

Each observer creates a detached form with three named text inputs containing the same supplied string. One is ordinary, one disabled and one readonly. The controls record shows all three values, but FormData contains only normal and readonly entries. The marked source and cleaned AB exhibit the same inclusion pattern. The missing disabled entry is therefore independent of the string edit. The browser excludes a control from this entry list while its value still exists on the element.

Readonly and disabled represent different export behavior

Both states can limit ordinary editing, yet their effects in this fixture differ at export. The readonly field remains represented with its current string, while the disabled field has no pair at all. The explicit empty control still produces two entries whose values are empty strings. An absent pair must consequently be distinguished from a present empty value when reading the destination schema. The retained-joiner control confirms that inclusion is not conditioned on whether a particular formatting character remains inside the text.

The export check can use an exact name list

In every measured fixture the expected three control names exist on the form, but only two names appear in the constructed entries. This gives a reproducible missing-field diagnosis without inspecting any server. The disabled value is neither overwritten nor converted to undefined. It is excluded at entry-list construction. A schema check can compare expected names with present entries before choosing an encoding. This observation does not prescribe enabling every disabled control; it establishes where this fixture loses the field.

Inspect names and flags alongside the data

Our fields have distinct nonempty names and are created in a known order. The saved control inventory makes the disabled and readonly flags observable instead of guessing from a visual screenshot. We do not submit the form or serialize an HTTP request. This experiment excludes disabled fieldsets, submit buttons, files, unchecked checkboxes, duplicate names and custom controls. Their entry-list rules require separate tests. Earlier JSON export guides concern object properties; this test concerns native HTML form controls before any JSON conversion exists.

Preserve required export fields intentionally

If a receiving workflow requires cleaned text, compare its expected named fields with the actual constructed entries. Retaining the string in a disabled control alone does not establish that FormData carries it. The browser download reproduces the native entry construction locally. The Node rerun independently checks the saved homepage callback and reuses recorded browser outputs for this stage. All strings are locally authored; no real user form or Claude document was sent. Export inclusion provides no evidence of authorship, detector acceptance or statistical watermark removal.

Reproduce this test

For a fresh native-control measurement, save and open reproduce-browser.html in your browser. It embeds the exact fixture observer and saved homepage script, runs locally, and shows its user agent. For the Node cleanup rerun, save reproduce.cjs, tested-app.js and browser-observations.json in the same folder. Run the command below with Node.js. The harness prints its runtime, script SHA-256 and every measured row. Compare those rows with the original record. Using a newer script or runtime creates a new experiment; retain the version information with your rerun.

node reproduce.cjs

Reference and next check

WHATWG HTML constructing-form-data-set provides the relevant primary definition. The table and fixture analysis are original measurements. For broader inspection, use our Unicode inspector. Read the scope distinction before interpreting cleanup as a watermark result.