Claude Watermark: find the hidden characters yourself

Runs offline Copy-paste script No upload

Short answer: a Claude watermark, in the practical sense, is a set of invisible Unicode characters that ride along with the text when you copy it out of Claude. You do not need any online tool to find them — you can list every one of them in your own file with the twelve-line script below, in about ten seconds.

The characters that actually show up are these:

Code pointNameWhat it does
U+200BZero Width SpaceBreaks a word without adding a visible space; also defeats spell check and word count
U+200CZero Width Non-JoinerBlocks a ligature, invisible
U+200DZero Width JoinerJoins characters; breaks grep and diff output
U+2060Word JoinerStops a line break; invisible
U+FEFFZero Width No-Break Space (BOM)At the start of a file it is a byte-order mark; inside text it is invisible
U+200E / U+200FLeft-to-Right / Right-to-Left MarkDirectional marks; reorder punctuation in some renderers
U+061CArabic Letter MarkSame family as the directional marks
U+00ADSoft HyphenHidden hyphen that appears only at a line break
U+034FCombining Grapheme JoinerInvisible, no effect on rendering
U+180EMongolian Vowel SeparatorLegacy separator, still invisible
U+202AU+202E, U+2066U+2069Bidirectional embedding / isolate controlsChange text direction from that point onward
U+2028 / U+2029Line / Paragraph SeparatorLooks like nothing, breaks CSV and JSON parsers
U+2061U+2063Invisible operators (function application, times, separator)Math-notation controls, invisible

Everything else you read about — "Claude adds a secret marker to every answer" — is a different topic. Statistical watermarks, if a provider uses them, live inside the model's output distribution, not inside your file. Nothing you can run on a .txt will find them, and nothing can strip them from text that is already written. What you can find and remove, deterministically, are the characters above.

Step 1 — list every invisible character in your file

Save this as find_watermark.py and run it against any UTF-8 text file. It walks the file character by character and prints the position, the code point and the Unicode name of everything invisible.

import unicodedata, sys

path = sys.argv[1] if len(sys.argv) > 1 else "draft.txt"
text = open(path, encoding="utf-8").read()

for i, ch in enumerate(text):
    if unicodedata.category(ch) in ("Cf", "Cc", "Zl", "Zp"):
        print(i, "U+%04X" % ord(ch), unicodedata.name(ch, "UNKNOWN"))

Run it like this:

python find_watermark.py draft.txt

Empty output means your file is clean. A list of code points is your evidence — keep the output, it is the "before" half of the before-and-after pair you will want if anyone ever asks.

The reason this works is that every invisible character in the table above belongs to Unicode general category Cf (format), Cc (control), Zl or Zp (separators). Normal letters, digits and punctuation never fall into those categories, so the script cannot produce false positives on ordinary prose.

If you would rather not install Python, the same check in one line:

Windows PowerShell

Select-String -Path draft.txt -Pattern "[\u200B-\u200F\u202A-\u202E\u2060-\u2063\uFEFF\u00AD]" -AllMatches

macOS / Linux

grep -oP "[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2063}\x{FEFF}\x{00AD}]" draft.txt | sort | uniq -c

Step 2 — find them where you actually work

This is the part most guides skip. Each editor behaves differently, and two of the three big ones simply refuse to show you these characters.

Microsoft Word (Windows). The button on the Home tab reveals paragraph marks, spaces and tabs — it will not reveal zero-width characters, so do not trust an empty-looking page. To find one anyway, put the cursor in the Find box (Ctrl+H), hold Alt and type 8203 on the numeric keypad: that inserts U+200B into the search field. Leave Replace empty and hit Replace All. Repeat with 8204, 8205, 8288 and 65279 for the other four common ones. This only works with a physical numeric keypad, and it will not catch the directional marks, which is why the script in Step 1 remains the reliable path.

Google Docs. There is no built-in inspector. The practical route is to paste with Ctrl+Shift+V (paste without formatting), which drops most invisible characters, and then export the document as plain text and run the Step 1 script on the export to confirm. If the export is clean, the document was clean.

VS Code. This one has a real inspector. Invisible characters are highlighted by default — you will see a thin box around them. The settings that control it are editor.unicodeHighlight.invisibleCharacters (default true), editor.unicodeHighlight.ambiguousCharacters and editor.unicodeHighlight.includeComments. Turn on editor.renderControlCharacters as well, and use Ctrl+F with the "Use Regular Expression" toggle and the pattern [\u200B-\u200F\u202A-\u202E\u2060-\u2063\uFEFF\u00AD] to jump straight to each one. This is the fastest way to clean a file you are about to commit.

Sublime Text / Notepad++. Notepad++ → View → Show Symbol → Show All Characters will show control characters but not the zero-width family; search with the same regex instead.

Step 3 — clean, then prove it worked

Cleaning is a one-liner once you know the set. This keeps the characters you want and drops the invisible ones:

import re, sys

path = sys.argv[1] if len(sys.argv) > 1 else "draft.txt"
text = open(path, encoding="utf-8").read()

pattern = re.compile(
    "[\u200B-\u200F\u202A-\u202E\u2060-\u206F"
    "\uFEFF\u00AD\u034F\u180E\u061C\u2028\u2029\uFFF9-\uFFFB]"
)
cleaned = pattern.sub("", text)
open(path, "w", encoding="utf-8").write(cleaned)
print("removed", len(pattern.findall(text)), "characters")

Then run the Step 1 script again on the same file. It should print nothing. That pair of outputs — the list before, the empty list after — is the only verification that means anything. A tool that says "cleaned!" without showing you what it removed has not told you anything.

Two cautions. First, do not run this on source code blindly: U+2028 and U+2029 have been legal inside JavaScript string literals since ES2019, but plenty of older parsers and line-based tools still treat them as line breaks, so removing them can change behaviour — read the diff before you commit. Second, keep a copy of the original until you have confirmed the output, because a blanket strip will also remove legitimate characters from non-Latin scripts that use U+200C and U+200D for correct rendering. If you need to do this across a whole folder, the batch script and git hook are in the folder cleanup guide.

What this site's tool removes, exactly

Our Claude Watermark Remover runs the same logic in your browser, with no upload. The list is fixed and published, so you can compare it against the code points you found:

It does not rewrite your wording, does not "humanise" anything, and does not add its own watermark. If you need the statistical layer handled, that is a writing problem, not a file problem.

Why the free online checkers are a bad habit

Search for a Claude watermark checker and most results are a text box on someone else's server. Whatever you paste is transmitted to that server, and for a draft, a contract, a support ticket or anything with a name in it, that is a bigger problem than the invisible characters you were trying to remove. The character set is not secret — it is a public part of Unicode, and it is printed in full on this page. Once the list is public, there is no reason to send your document anywhere to have it checked.

The script above runs locally. The tool on the home page runs locally. Neither one has a backend to leak from.

FAQ

Can I see a Claude watermark with my eyes?
No. Zero-width characters occupy no visual space by definition. If you can see it, it is not one of these characters — it is probably a real mark, a styling artefact, or a hyphenation soft hyphen that only appears at a line break.

Does finding one of these characters prove the text came from an AI?
No. The same characters appear in ordinary copy-paste from web pages, in exported PDFs, from Word's own autocorrect, and in text written on a phone keyboard. They are evidence that something invisible is in your file, not evidence about who wrote the words.

I removed them and a checker still flags my text. Why?
Because those checkers are looking at writing patterns — sentence rhythm, vocabulary, punctuation habits — not at invisible characters. Those two layers are independent. Stripping characters cannot change how a statistical detector scores your prose.

Does this affect code?
Yes, and code is where it hurts most. A U+200B inside an identifier makes two visually identical variables, breaks git diff and merge, and can make linters report a syntax error on a line that looks fine. Run the Step 1 script on any file before you commit it.

Is there a bulk option?
Run the cleaning script in a loop over a folder — it takes a file path as its argument, so for f in *.txt; do python clean.py "$f"; done handles a directory. Test on copies first.