CLAUDE WATERMARK REMOVER · METHOD TEST
Do trim() and normalize() remove hidden characters?
No: neither is a general hidden-character remover. In our 12 synthetic tests, trim(), a whitespace regex, NFC and NFKC all leave U+200B zero-width spaces, U+2060 word joiners and U+00AD soft hyphens intact. A targeted cleaner removes only its named characters. None of these tests verifies removal of Claude’s text watermark.
Open the Claude text cleaner Download measured results
One question, five methods
If you searched for a claude watermark remover because copied text fails an exact match, a shorter JavaScript command may seem enough. This experiment answers one narrower question: does each command remove the specific character in a known input? It does not investigate where a character came from.
We constructed 12 strings from explicit Unicode escapes. They are test fixtures, not samples collected from Claude. Each string passes independently through s.trim(), s.replace(/\s/g, ''), s.normalize('NFC'), s.normalize('NFKC') and the current homepage cleaner. The cleaner runs with “Remove invisible” enabled and dash mode set to “Keep”.
For the cleaner column, we executed the actual app.js with a minimal DOM harness, rather than substituting a broader regular expression. Its removal set is U+200B, U+00AD, U+2060, U+FEFF and U+034F. Our JSON record includes the script’s SHA-256 hash, runtime and complete outputs. Every table cell shows the full output as code points, including characters that look invisible.
Measured outputs for all 12 fixtures
| Fixture / input | trim() | /\s/g → empty | NFC | NFKC | Our cleaner |
|---|---|---|---|---|---|
Internal zero-width spaceU+0041 U+200B U+0042 | U+0041 U+200B U+0042 | U+0041 U+200B U+0042 | U+0041 U+200B U+0042 | U+0041 U+200B U+0042 | U+0041 U+0042 |
Edge zero-width spacesU+200B U+0041 U+200B | U+200B U+0041 U+200B | U+200B U+0041 U+200B | U+200B U+0041 U+200B | U+200B U+0041 U+200B | U+0041 |
Internal word joinerU+0041 U+2060 U+0042 | U+0041 U+2060 U+0042 | U+0041 U+2060 U+0042 | U+0041 U+2060 U+0042 | U+0041 U+2060 U+0042 | U+0041 U+0042 |
Internal soft hyphenU+0041 U+00AD U+0042 | U+0041 U+00AD U+0042 | U+0041 U+00AD U+0042 | U+0041 U+00AD U+0042 | U+0041 U+00AD U+0042 | U+0041 U+0042 |
Internal BOMU+0041 U+FEFF U+0042 | U+0041 U+FEFF U+0042 | U+0041 U+0042 | U+0041 U+FEFF U+0042 | U+0041 U+FEFF U+0042 | U+0041 U+0042 |
Leading BOMU+FEFF U+0041 | U+0041 | U+0041 | U+FEFF U+0041 | U+FEFF U+0041 | U+0041 |
Combining grapheme joinerU+0041 U+034F U+0042 | U+0041 U+034F U+0042 | U+0041 U+034F U+0042 | U+0041 U+034F U+0042 | U+0041 U+034F U+0042 | U+0041 U+0042 |
Non-breaking spaceU+0041 U+00A0 U+0042 | U+0041 U+00A0 U+0042 | U+0041 U+0042 | U+0041 U+00A0 U+0042 | U+0041 U+0020 U+0042 | U+0041 U+00A0 U+0042 |
Paragraph breakU+0041 U+000A U+0042 | U+0041 U+000A U+0042 | U+0041 U+0042 | U+0041 U+000A U+0042 | U+0041 U+000A U+0042 | U+0041 U+000A U+0042 |
Decomposed accentU+0065 U+0301 | U+0065 U+0301 | U+0065 U+0301 | U+00E9 | U+00E9 | U+0065 U+0301 |
Compatibility ligatureU+FB01 | U+FB01 | U+FB01 | U+FB01 | U+0066 U+0069 | U+FB01 |
Emoji with joinerU+1F469 U+200D U+1F4BB | U+1F469 U+200D U+1F4BB | U+1F469 U+200D U+1F4BB | U+1F469 U+200D U+1F4BB | U+1F469 U+200D U+1F4BB | U+1F469 U+200D U+1F4BB |
What the results mean for a broken paste
Zero-width space is not JavaScript whitespace. The internal and edge U+200B fixtures survive both trimming and the whitespace regex. They also survive both normalization forms. The homepage cleaner deletes U+200B, so A + U+200B + B becomes AB. If that hidden break separated two words, deletion can join those words; review the output before using it.
Location changes the BOM result. A leading U+FEFF disappears with trim(), but an internal one remains. The whitespace regex deletes it in either position. NFC and NFKC keep it. Our cleaner deletes it in both fixtures. This tests a character already inside a JavaScript string; it does not test file decoders or whether a file’s encoding marker should be retained.
Whitespace removal can damage structure. The regex deletes the U+00A0 between A and B and the U+000A paragraph break. Both outputs become AB. The homepage cleaner preserves both characters. NFKC converts the non-breaking space to U+0020 ordinary space, while NFC leaves it unchanged. Choose space conversion or paragraph editing deliberately rather than assuming it is invisible-character cleanup.
Normalization handles equivalence. NFC composes e + U+0301 into U+00E9. NFKC does that too and additionally changes the U+FB01 ligature into the letters f and i. The cleaner keeps these inputs unchanged. Normalization is useful for a different class of exact-match problem, but is not a replacement for selective removal.
The emoji fixture is preserved byte-for-byte as a string by every method here. Its U+200D joiner is outside our homepage removal set. This is evidence for this one sequence, not a test of every emoji or script. Joiners may be meaningful; a broader cleaner needs its own preservation tests.
Reproduce the measurements
Download the standalone Node.js harness and run node reproduce.cjs. It downloads the public homepage script, prints its hash and emits all 60 method outputs as JSON. Compare its hash with the saved record: later changes to the cleaner or runtime may change a rerun. For an offline repeat of this snapshot, download the tested script into the same directory and run node reproduce.cjs tested-app.js.
const sample = "A\u200BB";
console.log([...sample.trim()].map(c => c.codePointAt(0)));
// [65, 8203, 66]: the zero-width space is still there
console.log(sample.replace(/\u200B/g, ""));
// AB: targeted deletion; no inserted word separator
Choose the operation that matches the failure
For unwanted whitespace at the ends, trim() is suitable. For canonically equivalent spellings, consider NFC. For a named accidental hidden character, inspect the code points and remove only the characters you intend to change. The position-by-position inspector helps locate them. Keep an original copy and compare words, line breaks and meaningful joiners afterwards.
A clean character result does not identify an author, certify that a passage has no watermark or predict an AI detector score. These fixtures contain no known Anthropic watermark signal. See the separate Unicode and watermark explanation for that distinction.
Primary references
The ECMAScript trim specification defines trimming at the ends using WhiteSpace and LineTerminator. Its normalize specification defines the supported normalization forms. Unicode Annex #15 explains canonical and compatibility normalization. These references describe the operations; the table above is our own measured dataset.