CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why does String.raw keep \u200B after cleaning?
String.raw preserves the backslash escape spelling as ordinary characters. Our cooked template contains an actual U+200B and loses it; the raw spelling remains eight units. Newline controls show the same representation distinction.
Open the Claude text cleaner · Full measured data
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.
| Fixture and mode | Input string and code points | Output and cleaner status | Observed before / after |
|---|---|---|---|
| Raw escape spelling direct string / keep / invisible true | "A\\u200BB"U+0041 U+005C U+0075 U+0032 U+0030 U+0030 U+0042 U+0042 | "A\\u200BB"No selected invisible characters found | {"units":8,"containsMarker":false,"containsBackslash":true,"containsLF":false,"literalEscapeAt":1}{"units":8,"containsMarker":false,"containsBackslash":true,"containsLF":false,"literalEscapeAt":1} |
| Cooked escape character direct string / keep / invisible true | "AB"U+0041 U+200B U+0042 | "AB"Removed 1 invisible character | {"units":3,"containsMarker":true,"containsBackslash":false,"containsLF":false,"literalEscapeAt":-1}{"units":2,"containsMarker":false,"containsBackslash":false,"containsLF":false,"literalEscapeAt":-1} |
| Raw newline spelling direct string / keep / invisible true | "A\\nB"U+0041 U+005C U+006E U+0042 | "A\\nB"No selected invisible characters found | {"units":4,"containsMarker":false,"containsBackslash":true,"containsLF":false,"literalEscapeAt":-1}{"units":4,"containsMarker":false,"containsBackslash":true,"containsLF":false,"literalEscapeAt":-1} |
| Cooked newline direct string / keep / invisible true | "A\nB"U+0041 U+000A U+0042 | "A\nB"No selected invisible characters found | {"units":3,"containsMarker":false,"containsBackslash":false,"containsLF":true,"literalEscapeAt":-1}{"units":3,"containsMarker":false,"containsBackslash":false,"containsLF":true,"literalEscapeAt":-1} |
The template construction happens before the cleaner receives text
We author one raw template with the spelling backslash u200B between A and B and one ordinary cooked template with the equivalent source escape. The raw value contains eight units and a backslash, with the literal escape starting at index one. The cooked value contains three units and an actual marker. The cleaner leaves the raw value unchanged and reduces the cooked one to AB. Two newline controls distinguish a four-unit backslash n spelling from a three-unit string containing a line feed. Both newline values remain unchanged by this selected cleanup. The table records characters present in the runtime value rather than treating similar source notation as identical input.
Raw template text is not a Unicode escape interpreter
The cleaner receives an already constructed JavaScript string. It neither executes source code nor interprets escape notation. This makes the problem distinct from our JSON guide, where a parser decodes escapes in a document, and from Markdown literals, where a rendering context is involved. The reproducer embeds exact fixture strings and tests the resulting values; the authored construction remains available in the generation source. We do not evaluate arbitrary pasted templates, substitutions, invalid escapes or nested tags. Seeing u200B characters in an editor is insufficient evidence that the runtime value contains U+200B. Inspecting units, backslashes and code points resolves the representation in these four small examples.
Inspect values at the consumer boundary
When a test string appears to survive cleanup, capture the exact runtime value that reaches the callback and inspect its code points. Choose raw construction intentionally when documenting escape spellings; choose an actual character intentionally when testing character deletion. Do not replace arbitrary backslash sequences with characters as a general repair, because that would introduce a separate interpretation stage. Our raw newline control also demonstrates why a displayed escape may represent two characters rather than a line boundary. The saved downloads reproduce the runtime strings without executing user-provided text as code. They do not prove a source file, template engine or external editor uses the same escape rules. Keep source notation and its produced value together when reporting the problem.
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.cjsReference and next check
ECMAScript string operations 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.