Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Does assigning a fragment encode an existing percent escape again?

Our URL.hash setter retains A%20B, while encodeURIComponent of that same input produces A%2520B. A leading # is treated as the fragment marker, and empty text removes the fragment. Assign the intended representation deliberately.

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

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked fragment

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 run independently on the exact input and cleaned strings in the recorded Node runtime. 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 fragment
direct string / keep / invisible true
"A​B"
U+0041 U+200B U+0042
"AB"
Removed 1 invisible character
{"href":"https://example.test/p#A%E2%80%8BB","hash":"#A%E2%80%8BB","encodedWholeInput":"A%E2%80%8BB","decodedHash":"A​B"}
{"href":"https://example.test/p#AB","hash":"#AB","encodedWholeInput":"AB","decodedHash":"AB"}
Existing escape
direct string / keep / invisible true
"A%20B"
U+0041 U+0025 U+0032 U+0030 U+0042
"A%20B"
No selected invisible characters found
{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"A%2520B","decodedHash":"A B"}
{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"A%2520B","decodedHash":"A B"}
Leading hash
direct string / keep / invisible true
"#A B"
U+0023 U+0041 U+0020 U+0042
"#A B"
No selected invisible characters found
{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"%23A%20B","decodedHash":"A B"}
{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"%23A%20B","decodedHash":"A B"}
Empty fragment
direct string / keep / invisible true
""
""
No selected invisible characters found
{"href":"https://example.test/p","hash":"","encodedWholeInput":"","decodedHash":""}
{"href":"https://example.test/p","hash":"","encodedWholeInput":"","decodedHash":""}

The setter and component encoder process the same text differently

The marked AB fixture is assigned to the hash of a fresh HTTPS URL. Before cleanup the serialized fragment contains the UTF-8 percent bytes for U+200B; afterward it is simply #AB. Our existing-escape control supplies A%20B as literal input text. The setter retains that spelling in both hash and href, whereas encodeURIComponent turns the percent sign into %25. Decoding the serialized hash once yields A followed by a space and B. The two operations therefore cannot be substituted merely because both are associated with URL encoding.

A delimiter in the input changes how assignment is interpreted

The leading-hash control begins with # and contains a space. Assignment produces the same #A%20B fragment as the existing-escape reference, while whole-input component encoding also escapes the leading hash. Empty text yields an empty hash and the original path URL without a fragment marker. We save href as well as hash because an empty-looking fragment result needs its surrounding serialization to be interpreted. Every observer starts from the same fresh URL, so leftover state from a previous assignment cannot explain the outcome.

Track whether your value is raw text or an encoded fragment

Choose the representation accepted by the destination before pre-encoding a fragment or assigning it. Record the exact value supplied to the setter and the serialized result. This experiment uses valid percent sequences and one local decoding pass; it does not define behavior for malformed escapes, document navigation, browser history or anchor matching. The example domain is a parsing fixture and is never fetched. The earlier fragment guide starts with encoded text and asks where decoding happens. Here the new question concerns construction through the hash setter.

Cleanup only changes the string it receives

If an unwanted character is already represented by ASCII percent bytes, inspecting decoded content is a separate stage. That general boundary does not make every percent sequence unwanted. Our four authored controls preserve the exact distinction between raw marker text, existing escape text, a delimiter and empty content. No actual clipboard, Claude response or statistical detector participates. Treat the recorded URLs as reproducible serialization observations rather than proof that a destination link will scroll to a particular element or that any model-level watermark has been removed.

Reproduce this test

Save reproduce.cjs and tested-app.js 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 URL hash setter 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.