Close Menu
AI News TodayAI News Today

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    Text Watermarking in Python: Catch Whoever Copies Your Writing

    The Fairphone 6 Plus is the midrange phone we desperately needed

    German company becomes first in Europe to launch fully commercial orbital rocket

    Facebook X (Twitter) Instagram
    • About Us
    • Contact Us
    Facebook X (Twitter) Instagram Pinterest Vimeo
    AI News TodayAI News Today
    • Home
    • AI News
    • AI Reviews
    • AI Tools
    • AI Tutorials
    • Chatbots
    • Free AI Tools
    • Artificial Intelligence
    AI News TodayAI News Today
    Home»AI Tools»Text Watermarking in Python: Catch Whoever Copies Your Writing
    AI Tools

    Text Watermarking in Python: Catch Whoever Copies Your Writing

    By No Comments27 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Telegram Email
    Text Watermarking in Python: Catch Whoever Copies Your Writing
    Share
    Facebook Twitter LinkedIn Pinterest Email

    On August 2, 2026, Anthropic began watermarking every piece of text Claude produces. Since 2024, Gemini (Google) has used SynthID-Text, a method they published in Nature and later open-sourced. OpenAI built something similar. China has required embedded labels on AI-generated content since September 2025, and nearly 190 organizations have signed the EU’s transparency code.

    The result: billions of words generated from these systems every day carrying an invisible mark—not metadata that vanishes on copy-paste, but a signal baked into the words themselves.

    So if AI companies can do that, can you?

    Most people assume no. Images have pixels to tweak; audio has a spectrum. Text is just characters. If someone scrapes your writing and claims it, it’s your word against theirs.

    That assumption is wrong. A century ago, mapmakers, dictionary editors, and at least one very annoyed lyrics company figured this out long before language models existed.

    You can watermark plain text three ways, each leaving a detectable signal:

    • Invisible characters: easiest to add, easiest to erase. Any sanitizer or chatbot pass wipes them out.

    • Keyed word choices: specific substitutions based on a hidden key. Survives light editing, but a full rewrite kills it.

    • Meaning-level marks (rigged sampling): hardest to remove. It holds up better under rewriting, but the signal weakens. Durability always costs strength.

    A text watermark isn’t a visible stamp. It’s a pattern of choices only you know.

    1. Who this is for, and what you’ll get

    If you publish writing online and want more than a guess when it gets copied, this is for you.

    You’ll get:

    • A simple coin-flip intuition for three types of text watermarking.

    • An 80-line, standard-library-only script that embeds a 32-bit ID in text and detects it later.

    • A keyed word-choice watermark, a model-free detector, and a meaning-aware upgrade—plus where they fall short in practice.

    • Real-world survival tests across 12 channels, several editing attacks, full paraphrasing, and Chinese translation.

    • A practical rule for choosing the right watermark for the threat.

    Everything was tested on real models: Gemma-2-9b-it for watermarking and Qwen2.5-7B-Instruct for attacks, running on an NVIDIA GB10. The test set included 50 original paragraphs and 100 public-domain passages for false-positive checks.

    The scripts, corpus, and calibration data are all in text-watermarking-toolkit, so you can reproduce the results yourself.

    2. People have been watermarking text for a century

    Long before watermarking became cryptographic, it was used in a much simpler way: hide a tiny, deliberate mistake or variation, then see who copies it.

    Figure 1 — A century of text watermarking, split by what does the recognising. Above the 2006 line, marks were planted by hand and spotted by a human who knew what to look for; below it, both halves become a key and a hypothesis test. Image by author.

    2.1 Trap streets

    One example is from mapmakers.

    Mapmakers inserted fake streets, towns, or landmarks into maps. If the same fake feature appears on a competitor’s map, the source of the copying is obvious.

    In 1925, the General Drafting Company added a fake New York town called Agloe, named from its founders’ initials. Years later, a store opened at the crossroads and adopted the name. The fictional town had effectively become real.

    Figure 2 — The trap street. One invented street costs the map nothing and eventually becomes the copy of others. Image by author.

    2.2 Mountweazels

    Reference books use the same trick with fake entries.

    The New Columbia Encyclopedia famously included Lillian Virginia Mountweazel, a fictional photographer with an elaborate biography. The New Oxford American Dictionary later planted esquivalience, supposedly meaning “the wilful avoidance of one’s official responsibilities.”

    Neither was real. Both were bait: if another reference work reproduced them, that was evidence of copying.

    Figure 3 — The mountweazel. Same idea in a reference book: a word with no referent cannot be independently researched, only copied. Image by author.

    2.3 Canary traps

    A canary trap takes the idea one step further. Instead of giving everyone the same fake detail, each recipient gets a slightly different version.

    If the document leaks, the variation identifies whose copy it came from.

    Elon Musk has said Tesla used this technique in 2008 by varying whether sentences were separated by one space or two. Those tiny differences formed a binary signature unique to each recipient.

    Figure 4 — The canary trap. Every recipient gets the same words and a different invisible pattern, so a leaked copy names the leaker. Image by author.

    2.4 Genius vs. Google

    The most important example here is one where the watermark apparently worked — but the lawsuit still failed.

    Lyrics site Genius suspected Google was reproducing its transcriptions in search results. Genius began alternating straight and curly apostrophes in a pattern that, when read as Morse code, spelled REDHANDED.

    The pattern was seeded into 301 songs and reportedly appeared in Google’s results for 116 of them.

    Genius later used a second watermark based on different types of spaces, encoding the word Genius.

    Figure 5 — Genius’s apostrophes. Straight is a dot, curly is a dash, and the sequence spells REDHANDED in Morse: the last hand-planted watermark in the story, and the first carrying a real payload. Image by author.

    It sued Google for $50 million in 2019. The case was dismissed in 2020, not because the watermark failed, but because Genius did not own the underlying lyrics; it licensed them.

    That distinction matters:

    A watermark can show that your version of a text was copied. It cannot, by itself, prove that you owned the text in the first place.

    3. The coin-flip analogy

    Imagine that while writing, you repeatedly make a hidden binary action: insert one of two invisible characters, choose between two synonyms, or pick between two equally plausible next words.

    One matching choice proves nothing: it has a 50% chance of happening by accident. But if 30 choices match the key in a row, the odds of that happening randomly are roughly 1 in a billion.

    That probability is what gives the watermark statistical evidence. In formal terms, it can be expressed as a p-value.

    Figure 6 — The coin-flip analogy. The same sentence either way; only the pattern of choices differs, and only someone holding the key can see it. Sixteen coins at 14 hits clears a 1%-false-positive threshold, which is also why short text is the hard case. Image by author.

    The three watermarking families mainly differ in what the “coin flip” represents:

    Family

    The coin

    Where it lives

    Invisible characters

    a zero-width character — present or absent

    between the letters

    Keyed word choices

    “big” vs. “large”; straight vs. curly apostrophe

    in the words

    Rigged sampling

    which token the model emits next

    inside the generator

    The first two can be applied to text that already exists. The third must happen while a language model is generating the text.

    3.1 Technique 1 — invisible characters

    Unicode includes characters that occupy zero visible space. Two examples are:

    • U+200B — zero-width space

    • U+200C — zero-width non-joiner

    Both are legitimate Unicode control characters, but in ordinary Latin text they are effectively invisible.

    Assign one character to 0 and the other to 1, and you have a hidden binary channel inside normal-looking text.

    Zach Aysan described this technique in 2017 and pointed out an important consequence: copied text can carry an invisible fingerprint with it. Someone pasting a leaked document elsewhere could unknowingly preserve the identifier embedded inside it.

    Figure 7 — Technique 1 end-to-end. Two invisible characters carry a 32-bit ID plus a CRC, repeated after every sentence, and one line of code removes all of it. Image by author.

    How the implementation stays reliable

    Here’s the implementation that I ran the experiments with.

    """Invisible-ink watermarking for plain text, using zero-width Unicode characters."""import reZERO, ONE = "​", "‌"   # zero-width space, zero-width non-joinerID_BITS, CRC_BITS = 32, 8PAYLOAD_BITS = ID_BITS + CRC_BITS# Insert a payload after sentence-ending punctuation that is followed by a space.SENTENCE_END = re.compile(r"(?<=[.!?])(?=s)")def crc8(value: int, bits: int = ID_BITS) -> int:    """CRC-8/ATM (polynomial 0x07) over `bits` bits of `value`, MSB first."""    crc = 0    for i in reversed(range(bits)):        crc ^= ((value >> i) & 1) << 7        crc = ((crc << 1) ^ 0x07) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF    return crcdef embed(text: str, owner_id: int) -> str:    """Return `text` with an invisible copy of `owner_id` after every sentence."""    bits = f"{owner_id:0{ID_BITS}b}{crc8(owner_id):0{CRC_BITS}b}"    mark = "".join(ONE if b == "1" else ZERO for b in bits)    marked = SENTENCE_END.sub(mark, text)    return marked if mark in marked else text + markdef strip(text: str) -> str:    """Remove every zero-width watermark character. This is the sanitizer."""    return text.replace(ZERO, "").replace(ONE, "")def extract(text: str) -> int | None:    """Recover the owner ID, or None if no payload passes its CRC check."""    votes: dict[int, int] = {}    for run in re.findall(f"[{ZERO}{ONE}]+", text):        bits = "".join("1" if ch == ONE else "0" for ch in run)        for start in range(0, len(bits) - PAYLOAD_BITS + 1):            window = bits[start : start + PAYLOAD_BITS]            owner_id = int(window[:ID_BITS], 2)            if crc8(owner_id) == int(window[ID_BITS:], 2):                votes[owner_id] = votes.get(owner_id, 0) + 1    return max(votes, key=votes.get) if votes else None

    Three choices do most of the work.

    1. A checksum prevents false matches.
    Without validation, any random sequence of zero-width characters could decode into an apparent ID. Adding an 8-bit CRC reduces the chance of a random payload passing validation to about 1 in 256. Across 1,700 extraction attempts in these experiments, there were zero false IDs.

    2. The payload is repeated.
    A 40-bit identifier requires 40 invisible characters. Repeating it after each sentence means even a copied paragraph can still contain a complete, decodable mark.

    3. The decoder uses sliding windows.
    Copying can merge, truncate, or misalign invisible-character sequences. Instead of assuming perfect formatting, the decoder tests every possible 40-bit window and returns the valid ID that appears most often.

    What it looks like

    Before

    The report is confidential. Please do not forward it to anyone outside the team.

    After

    Visually, it looks identical. Internally, the text contains repeated zero-width characters encoding the identifier.

    extract() → 0xc0ffee01

    In this example, 80 invisible characters were added with no visible change. When the text is copied, those characters can travel with it because the clipboard treats them as ordinary text.

    To find out, I tested 150 marked paragraphs per channel across 11 mechanical transformations and one language model, checking whether the exact 32-bit ID survived.

    Figure 8 — Zero-width watermark survival by channel. The mark is untouched by every format conversion and every normalizer tested, and destroyed by the two things that rewrite characters: an explicit sanitizer, and an LLM asked to tidy the text. Image by author.

    What survives

    Against systems that simply move or reformat text, the watermark was extremely robust: 150/150 recovered through every tested mechanical channel, including:

    • copying only the middle 50% of a paragraph

    • UTF-8 and UTF-16 conversions

    • JSON and HTML round trips

    • Unicode NFKC normalization

    Two results are worth noting. Python’s s does not remove U+200B, because it is a Unicode format character rather than a normal space. NFKC normalization leaves it intact too.

    What kills it

    • Explicit sanitization: 0/150 survived.
      If someone knows which zero-width characters to remove, a simple replacement strips the watermark completely.

    • Language-model cleanup: 4/50 survived — just 8%.
      I only asked the model to fix typos and formatting while preserving the wording. But language models generally regenerate text rather than edit the original character stream, so the invisible characters disappear. With full paraphrasing, survival went down to 0/50.

    That gives technique 1 a simple limit:

    It survives text transport. It does not survive text rewriting.

    3.2 Technique 2 — keyed word choices

    The second technique hides information inside the wording itself rather than between characters. In other words, we write constantly equivalent choices:

    • big/large

    • begin/start

    • problem/issue

    In normal practice, a writer chooses whichever sounds best. However, with a keyed watermark, a secret key determines which acceptable alternative to use.

    The major advantage over zero-width characters is that there is nothing extra to strip. The watermark is part of the text itself.

    Figure 9 — Technique 2. The key decides which member of each interchangeable pair belongs at each slot. Nothing is hidden in the text, so there is nothing for a sanitizer to strip. Image by author.

    Sanitizers, Unicode normalization, scrapers, and file conversions cannot remove it. To destroy the signal, you generally have to rewrite the words themselves.

    3.2.1 The mechanism

    Start with a public table of interchangeable word pairs. At each eligible word, use a secret key to choose which member of the pair should appear.

    def keyed_bit(key: bytes, context: str, pair: tuple[str, str]) -> int:    """Which member of a pair the key selects at a slot with this left context."""    message = f"{context}|{pair[0]}".encode("utf-8")    return hmac.new(key, message, hashlib.sha256).digest()[0] & 1

    If the bit is 0, use the first word. If it is 1, use the second. Existing words that already match the key stay unchanged; mismatches are swapped only when the sentence still reads naturally.

    def detect(text: str, key: bytes) -> dict:    """How many slots land on the key's side, and how surprising is that?"""    slots = scan(text, key)    n = len(slots)    hits = sum(slot["on_key"] for slot in slots)    z = (hits - n / 2) / math.sqrt(n / 4) if n else 0.0    p = 0.5 * math.erfc(z / math.sqrt(2)) if n else 1.0    return {"slots": n, "hits": hits, "z": z, "p_value": p}

    With the wrong key—or ordinary unmarked text—each choice should match the key about 50% of the time. A marked document produces an unusually high number of matches.

    Two details matter

    Use stable context.
    The key cannot depend on a nearby word that might itself be swapped, or where embedding one bit changes the next one. I instead use the nearest preceding word that is not in the synonym table.

    Hash the pair identity too.
    Hashing only the context creates correlations when the same context repeats. Including the word pair keeps slots independent enough for the binomial test to behave properly.

    After that fix, 100 human-written passages tested under 20 keys produced null z-scores with mean 0.007 and standard deviation 1.020—almost exactly what the statistical model predicts.

    3.2.2 How well does it work?

    I tested 50 paragraphs under three keys, using Gemma-2-9B-IT to reject swaps that changed meaning or grammar.

    It accepted 880 of 1,039 swaps (84.7%), changing about 2.72% of all words.

    At a calibrated 1% false-positive rate, detection required roughly z ≥ 2.45.

    Figure 10 — Detector z-scores for marked text against unmarked human text. At paragraph length the two distributions overlap and a quarter of marked paragraphs fall below the threshold; at article length they don’t overlap at all. Length is the whole game. Image by author.

    And here’s the result with an interesting view:

    Text length

    Slots

    Mean z

    Detected at 1% FPR

    One paragraph (~215 words)

    12.9

    +2.93

    73.3% (per-seed 68–78%)

    One article (~1,075 words)

    64.3

    +6.66

    100.0% (per-seed 100%)

    Unmarked human text

    —

    −0.27

    0.0%

    The main limitation is sample size. A single paragraph had only about 13 usable slots. Even a perfect 13-for-13 match reaches only about z = 3.6, leaving little room for noise.

    Across five paragraphs, though, the average rose to 64 slots, with z around +6.66 and perfect detection in the test set.

    The practical takeaway: word-choice watermarks work at document length, not tweet length.

    3.2.3 Detection ratio across techniques

    Figure 11 — Detection after four editing attacks and a full rewrite, at paragraph length. Moderate edits degrade the mark gracefully; a paraphrase removes it completely. Bars show the mean, vertical lines the spread across three keys. Image by author.

    Attack

    Detected

    Mean z

    Clean copy

    73.3%

    +2.93

    Sentence deletion 30%

    53.3%

    +2.48

    Word replacement 10%

    42.7%

    +2.22

    Partial copy (middle 50%)

    28.7%

    +1.88

    Word replacement 30%

    10.0%

    +1.13

    Full paraphrase

    0.0%

    −0.29

    Deleting 30% of sentences still left about half the paragraphs detectable because surviving slots kept their original bits.

    Partial copying performs worse mostly because there are too few observations. Half a paragraph may contain only six slots, and six coin flips cannot produce enough statistical evidence to cross the detection threshold.

    In contrast, a full paraphrase is different. Detection fell to 0%, with mean z = −0.29—essentially the null distribution because the paraphraser made fresh word choices, effectively re-flipping every coin.

    3.2.4 The hidden cost: text quality

    The bigger problem is that a technically valid synonym is not always a good replacement.

    Examples from the experiment included:

    “Two dollars of filtered water repaired a issue I had thrown multiple hundred dollars at.” (original: fixed a problem I had thrown several hundred dollars at)

    and

    “a water heater failed and price me a ceiling” (original: cost me a ceiling)

    The substitutions are understandable, but obviously worse. cost → price, for example, works in some noun contexts and fails as a verb.

    To measure that cost, I used Qwen2.5-7B-Instruct as an independent evaluator.

    Keyed synonym

    Semantic (k=4)

    Mean log-prob change per token

    −0.1324

    +0.0013

    Passages that got less fluent

    100% (150/150)

    55.3%

    New a/an agreement errors

    28, in 26/150 passages (17.3%)

    1, in 1 passage

    Length change

    +0.0%

    +15.8%

    The result was clear:

    • Every marked paragraph became less probable under the language model.

    • The average paragraph contained 5.9 swaps.

    • About 1 in 6 paragraphs gained a grammatical error.

    So the tradeoff is straightforward:

    more forced word choices → stronger statistical signal → greater risk to the writing quality.

    The safest version uses a small, hand-audited set of genuinely interchangeable pairs—and still requires a human read before publication.

    3.3 Technique 3 — marking the meaning

    The first two techniques fail under paraphrasing for the same reason: the watermark lives in the wording. Rewrite the wording, and the mark disappears.

    So what if the watermark lived in the meaning instead?

    That is the idea behind PostMark (Chang et al., EMNLP 2024) and a similar embedding-based approach described by Jina AI.

    Here is the flow:

    1. Keep a secret list of uncommon words.

    2. Use an embedding model to find which words are most semantically related to the document.

    3. Ask a language model to weave a few of those words naturally into the text.

    If the meaning stays similar, the same rare words remain relevant — and because those words now carry actual content, a rewriter may keep them.

    Figure 12 — Technique 3. The document’s meaning selects which secret words it should carry, so a paraphrase that preserves the meaning tends to select the same words. Tends to, at about one rewrite in three. Image by author.

    For my experiments, I used BAAI/bge-m3, a multilingual embedding model. I did not use jina-embeddings-v3 because of its non-commercial license.

    3.3.1 Getting the detector right

    My first detector looked strong — until I tested it on clean text.

    It compared semantic keywords from the suspect text with the planted watermark words and flagged 62.7% of translated samples.

    But it also flagged 100% of the unwatermarked originals.

    Why? Both sets reflected the document’s meaning, so the detector was measuring semantic similarity, not the watermark.

    “Is this semantically the same document?”

    not

    “Does this document contain a watermark?”

    The valid black-box detector

    PostMark’s actual detector needs only the suspect text. It:

    • Understands the text’s meaning. It converts the suspect text into an embedding—a numerical representation of its semantic meaning.

    • Uses that meaning to select secret words. From its secret table, it finds the k words most semantically related to the text. Here, k just means some predetermined number, such as 20.

    • Counts matches. It checks how many of those selected secret words actually occur, literally, in the suspect text.

    Unmarked text rarely contains these uncommon words by coincidence. However, watermarked text does. Using a threshold calibrated to about a 1% false-positive rate, this became the detector I report.

    3.3.2 Results: robustness comes at a cost

    With k = 4 words per paragraph, Gemma-2-9b-it successfully inserted 93.5% of the requested words, while increasing text length by 15.8%.

    Condition

    Black box (no original)

    Presence (needs original)

    Clean copy

    99.3%

    100.0%

    Word replacement 30%

    60.0%

    99.3%

    Partial copy 50%

    40.7%

    67.3%

    Translated to English and back

    23.3%

    68.0%

    Full paraphrase

    9.3%

    32.7%

    Translated to Chinese

    0.0%

    0.7%

    Unmarked original

    0.7%

    4.0%

    Clean detection was nearly perfect, even on a single paragraph.

    Paraphrasing was much harder:

    • 9.3% black-box detection after rewrite

    • 32.7% with a detector allowed to reference the original

    • 0% after direct Chinese translation

    The translation result is unsurprising: the planted English words disappear. A multilingual embedding model can still recognize the meaning, but semantic similarity alone is not proof of a watermark.

    The weak paraphrase result at k=4 also turned out to be partly a configuration issue. With only four planted words, losing one word changes the score dramatically.

    So I repeated the same experiment with k = 12.

    k=4

    k=12

    Words planted (of requested)

    93.5%

    80.6%

    Clean copy

    99.3%

    100.0%

    Full paraphrase

    9.3%

    36.7% (per-seed 34–40%)

    Unmarked original

    0.7%

    0.7%

    Paraphrase survival improved by roughly 4×, while the measured false-positive rate stayed around 0.7%.

    That leads to a more useful conclusion:

    Semantic watermarking becomes more resistant to paraphrasing as you insert more watermark-bearing content.

    But that robustness has a cost. At k=12, the model inserted only 80.6% of the requested words, down from 93.5% at k=4. Working a dozen unusual words into roughly 215 words of prose starts to affect naturalness.

    Figure 13 — The three families before and after a full paraphrase by a different model, all scored by detectors that don’t get to see the original. Marking meaning is the only thing that outlasts a rewrite at all: 9% at k=4, rising to 36.7% at the heavier k=12 insertion rate. Image by author.

    In other words, the trade-off is:

    more watermark → better robustness → more rewriting and worse readability

    At a practical insertion rate, the method detected roughly a third of paraphrased passages in my tests. That was substantially better than the other watermark families I tested, but still far from reliable enough for something like a legal attribution claim.

    Reproduction caveat

    This was a partial reproduction, not a direct replication of PostMark.

    PostMark uses GPT-4o for word insertion. I used a 9B open model, ~215-word passages, and an intentionally aggressive paraphraser.

    3.4 Technique 4 — rigged sampling

    The earlier techniques can be added to text after it is written. This one is the opposite. It has to happen while the language model is generating each token.

    A language model writes by repeatedly choosing the next token from a probability distribution. Each choice is effectively a coin flip, and a page of text contains thousands of them. The watermark works by rigging those random choices in a way only the detector can recognize.

    Scott Aaronson described the core idea in 2022, based on work with OpenAI engineer Hendrik Kirchner: keep the model’s normal probabilities, but replace ordinary randomness with keyed pseudorandomness based on a secret key and the preceding tokens.

    To a reader, the output looks normal. To someone with the key, the sequence contains a detectable statistical pattern.

    Figure 14 — Technique 4. The key splits the vocabulary and nudges one half up at every position. Quality holds because there was rarely one correct next word, which is also why the mark vanishes when there was. Image by author.

    There are two major approaches: green-list watermarking and tournament sampling.

    3.4.1 Kirchenbauer et al. — green-list watermarking

    At every step, the vocabulary is split pseudorandomly into a green list and a red list. Green tokens receive a small probability boost.

    The model still has many reasonable words to choose from, but over hundreds of tokens it selects green words more often than chance predicts.

    Detection is simple: count the green tokens and calculate a z-score.

    3.4.2 SynthID-Text — tournament sampling

    DeepMind’s SynthID-Text uses a different method. It samples several candidate tokens and runs them through a pseudorandom tournament to decide which one wins.

    Its key advantage is a non-distortionary mode, designed so the overall token distribution remains unchanged. SynthID-Text is used with Gemini and is available in open-source tooling.

    3.4.3 Other watermarking techniques

    Meta’s watermarking research added stronger statistical guarantees and support for multi-bit payloads.

    A more surprising result came from Watermarking Makes Language Models Radioactive: researchers found that a watermark could remain statistically detectable in a new model trained partly on watermarked text. In their experiments, the effect was measurable with only 5% contaminated training data.

    OpenAI also developed a text watermark that reportedly performed very well internally on long passages, but did not release it. Its stated concerns included translation, paraphrasing, and simple character-level edits — the same attacks that weaken most text watermarks.

    3.4.4 Does it hold up?

    I tested Kirchenbauer and SynthID using Gemma-2-9b-it on the same 30 prompts:

    • 20 open-ended prompts

    • 10 factual prompts

    • 3 random seeds

    • 400 tokens per response

    • Detection tested at 50, 100, 200, and 400 tokens

    • Thresholds calibrated to a 1% false-positive rate

    The biggest finding was not which watermark won. It was how much freedom the model had while writing.

    Figure 15 — Detection rate against the number of tokens the detector sees, for both schemes, split by how much freedom the model had. On creative text both schemes get there; on factual text the watermark has almost nothing to hold onto. ✕ marks detection after a paraphrase at 400 tokens. Image by author.

    On open-ended prompts, both schemes worked well.

    Tokens seen

    Kirchenbauer

    SynthID-Text

    50

    28.3%

    60.0%

    100

    53.3%

    86.7%

    200

    78.3%

    96.7%

    400

    95.0%

    100.0%

    SynthID was stronger at every tested length. It reached at roughly 200 tokens the detection performance Kirchenbauer needed about 400 tokens to achieve.

    At 400 tokens, SynthID detected 100% of the watermarked open-ended generations in this experiment.

    Tokens seen

    Kirchenbauer

    SynthID-Text

    50

    0.0%

    30.0%

    100

    0.0%

    33.3%

    200

    3.3%

    76.7%

    400

    50.0%

    76.7%

    The lesson is simple:

    More tokens + more possible word choices = more signal.

    On factual prompts, both methods performed poorly.

    Consider:

    List the eight planets in order.

    There is very little freedom in what comes next. The model cannot favor a watermarked token if doing so would make the answer wrong.

    No choice means no useful coin flip. No coin flips means no watermark signal.

    This is one of the biggest limitations of generative watermarking: it is naturally weak on short text, factual answers, code, and other highly constrained outputs.

    Repetition also causes problems. In my factual tests, unmarked outputs produced unusually unstable detection scores because forcing simple factual answers to 400 tokens led the model to repeat itself, breaking some of the statistical assumptions behind detection.

    Paraphrasing removes most of the signal. The biggest practical weakness was rewriting. After passing the 400-token watermarked outputs through Qwen2.5-7B-Instruct for paraphrasing, detection on open-ended text fell from:

    • Kirchenbauer: 95.0% → 23.3%

    • SynthID: 100% → 11.7%

    On factual text, both fell to 0%.

    That matches the broader weakness of this entire technique: the watermark belongs to the model’s original token choices. Once another model rewrites those choices, much of the statistical pattern disappears.

    Arm

    Throughput

    Overhead

    plain

    110.5 tok/s

    —

    SynthID-Text

    82.2 tok/s

    −25.6%

    Kirchenbauer

    54.6 tok/s

    −50.6%

    Generation cost

    In naive implementations, watermarking also adds computation during every generation step.

    The reference implementations in transformers perform extra processing repeatedly in Python, so benchmark numbers should be treated as an upper bound, not as the cost of an optimized production system.

    The useful comparison is relative:

    Tournament sampling was cheaper than green-list watermarking in my tests, but neither was free.

    Large providers can integrate the same logic much deeper into their serving infrastructure, reducing that overhead substantially.

    Practical takeaway

    Generative watermarking works best when text is long, open-ended, and left mostly unchanged. It becomes much weaker when the output is short, factual, repetitive, translated, or paraphrased.

    So if an LLM is producing creative text and you want the original output to be traceable, these schemes can work remarkably well.

    But if someone rewrites the text — or the model had little freedom to begin with — there may simply not be enough statistical signal left to detect.

    3.4.5 The detection toolkit

    If you find a page that looks suspiciously like yours, run:

    python detect-watermark.py suspect.txt --key "my-secret-key"

    Real output, on a marked article:

    Checking 1,127 words.  [ -- ] No invisible characters. Nothing hidden between the letters.  [HIT ] KEYED WORD PATTERN FOUND - 80 of 80 word choices match your key         (z = 8.94, p = 1.9e-19). Chance alone would do this in less than         one unmarked text in a trillion.VERDICT: this text carries a watermark.Remember what that means: it is strong evidence of copying, not proof ofownership. Genius caught Google with a watermark and still lost in court.

    And on a clean passage nobody ever marked:

      [ -- ] No invisible characters. Nothing hidden between the letters.  [ -- ] Word choices look ordinary - 17 of 36 match your key (z = -0.33).         That is what unmarked text looks like.VERDICT: no watermark found.

    What it checks

    The detector can run three checks:

    • Zero-width watermark: decodes any hidden payload and reports the owner ID.

    • Keyed watermark: with --key, recomputes each keyed slot and applies a z-test, flagging results at z ≥ 2.45.

    • Semantic watermark: with --semantic words.json, runs the embedder. If the dependency is missing, it fails gracefully with an install hint.

    4. Which watermark for which threat

    These techniques don’t really compete. They fail under different attacks. So the useful question isn’t which watermark is best? It’s what are you defending against?

    Figure 16 — The decision rule, with the measurement behind each branch. Every rate shown is from this article’s runs, not from the source papers. Image by author.

    Your threat

    Use

    Why

    Scrapers and content farms republishing verbatim

    Zero-width

    100% through HTML, JSON, Markdown, docx; decodes from half a paragraph

    Finding which recipient leaked a document

    Zero-width, unique ID per copy

    32 bits = 4 billion possible recipients; the CRC means no false accusations

    Someone republishing with light edits

    Keyed word choices

    Nothing to strip; survives 30% sentence deletion at 53%

    Someone running your text through an LLM

    Semantic, at a heavy insertion rate

    36.7% after paraphrase at k=12 (9.3% at k=4) — the best on offer, not a guarantee

    Proving a specific unusual claim was yours

    Canary trap

    Free, no code, survives rewriting if the detail is load-bearing

    Marking text your own LLM generates

    SynthID or Kirchenbauer

    Built into transformers; needs generation-time control

    Proving you own the text in court

    None of the above

    This is a legal problem, not a technical one. Ask Genius.

    Four practical rules

    • Mark at article length, not paragraph length.
      The keyed word mark rises from 73.3% detection at 215 words to 100% at 1,075 words. More text is the cheapest robustness you can buy.

    • Layer independent marks.
      Zero-width characters and keyed word choices don’t interfere with each other. A sanitizer that removes one can leave the other completely intact.

    • Calibrate on unmarked text first.
      Set thresholds using human-written text you never watermarked. I tested against 100 unmarked passages; that check exposed a detector that otherwise looked reliable.

    • Save the key when you publish.
      Record the key, ID, or word list used for each watermark. You’ll need it later to verify the mark.

    If you can’t reproduce the detection, you don’t really have a watermark.

    5. References and resources

    Core techniques

    • A Watermark for Large Language Models — Kirchenbauer, Geiping, Wen, Katz, Miers, Goldstein, 2023 · arXiv:2301.10226. The green/red list scheme; implemented in transformers as WatermarkingConfig.

    • Scalable watermarking for identifying large language model outputs (SynthID-Text) — Dathathri et al., Nature 634, 818–823, October 2024 · doi:10.1038/s41586-024-08025-4. Tournament sampling with a non-distortionary mode; google-deepmind/synthid-text, License Apache-2.0.

    • PostMark: A Robust Blackbox Watermark for Large Language Models — Chang, Krishna, Houmansadr, Wieting, Iyyer, EMNLP 2024 · arXiv:2406.14517. The semantic watermark this article reimplements at small scale.

    • Three Bricks to Consolidate Watermarks for Large Language Models — Fernandez, Chaffin, Tit, Chappelier, Furon, WIFS 2023 (Best Student Paper) · arXiv:2308.00113. Grounded statistical tests with guaranteed FPR, and multi-bit payloads.

    • Watermarking Makes Language Models Radioactive — Sander, Fernandez, Durmus, Douze, Furon, NeurIPS 2024 · arXiv:2402.14904. Watermark traces survive into models trained on the marked text.

    • The hiding virtues of ambiguity: quantifiably resilient watermarking of natural language text through synonym substitutions — U. Topkara, M. Topkara, Atallah, MM&Sec ’06 · doi:10.1145/1161366.1161397. The ancestor of technique 2.

    • Watermarking GPT outputs — Scott Aaronson (with Hendrik Kirchner), 2022 · talk slides. The keyed-pseudorandomness proposal.

    • A Survey of Text Watermarking in the Era of Large Language Models — Liu, Pan, Lu, Li, Hu, Zhang, Wen, King, Xiong, Yu · ACM Computing Surveys 57(2), Article 47, 2024 · doi:10.1145/3691626 · arXiv:2312.07913.

    Models used

    • google/gemma-2-9b-it — 9B instruction-tuned model; planted the keyed and semantic marks and generated Exp 3. Gated weights under the Gemma Terms of Use.

    • Qwen/Qwen2.5-7B-Instruct — 7B instruction-tuned model; ran every paraphrase, translation and readability score, so the attacker is never the model that planted the mark. License Apache-2.0.

    • BAAI/bge-m3 — multilingual embedding model, License MIT. Chosen over jina-embeddings-v3, which is CC-BY-NC and is cited here as prior art only.

    Data

    • Corpus (50 blog paragraphs, 203–235 words). Written by the author for this article; no third-party licence applies.

    • Negatives (100 passages, 150–299 words). Project Gutenberg, public domain — 10 passages each from Pride and Prejudice, Alice’s Adventures in Wonderland, Moby Dick, Frankenstein, The Adventures of Sherlock Holmes, A Tale of Two Cities, The Picture of Dorian Gray, Dracula, Heart of Darkness, and A Doll’s House. Gutenberg header and footer stripped before use.

    Industry and regulation

    • Anthropic, “Claude’s text watermark”, August 2, 2026 · anthropic.com/news/claude-text-watermark

    • OpenAI’s unreleased text watermark, reported by the Wall Street Journal, August 2024 (secondary coverage: Tom’s Hardware, Engadget)

    • EU AI Act Article 50 and the Code of Practice on Transparency of AI-generated Content, July 2026 (~190 signatories) · European Commission

    • China CAC “Measures for Labeling AI-Generated Content” and mandatory standard GB 45438-2025, effective September 1, 2025 · Covington Inside Privacy

    The stories

    • Genius vs Google: CNBC on the suit; TechCrunch on the August 2020 dismissal.

    • Tesla’s 2008 canary-trap emails, per Musk’s own account · The Intercept. Other accounts of the incident differ.

    • Mountweazels, esquivalience, trap streets and Agloe · Wikipedia, “Fictitious entry”

    • Zach Aysan, “Fingerprinting with Zero-Width Characters”, December 2017 · zachaysan.com

    • Thinkst Canarytokens — free honeytokens including Word-document beacons, DNS tokens and fake AWS keys · canarytokens.org

    Tooling

    • MarkLLM — open toolkit implementing many watermarking schemes with a visualization layer; THU-BPM, EMNLP 2024 demo · arXiv:2405.10051 · THU-BPM/MarkLLM. Worth a look if you want to compare schemes beyond the two built into transformers.

    • Hugging Face, “AI Watermarking 101” · huggingface.co/blog/watermarking

    Catch Copies Python text watermarking writing
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous ArticleThe Fairphone 6 Plus is the midrange phone we desperately needed
    • Website

    Related Posts

    AI Tools

    Linear Discriminant Analysis (LDA) in Real-Life: Dimensionality Reduction in a Real-Estate Dataset

    AI Tools

    DeepSeek Just Proved Open-Source Reasoning Can Match OpenAI—Here’s How

    AI Tools

    Decktopus AI: Why I’d Never Build a Presentation From a Blank Slide Again

    Add A Comment
    Leave A Reply Cancel Reply

    Top Posts

    Text Watermarking in Python: Catch Whoever Copies Your Writing

    0 Views

    The Fairphone 6 Plus is the midrange phone we desperately needed

    0 Views

    German company becomes first in Europe to launch fully commercial orbital rocket

    0 Views
    Stay In Touch
    • Facebook
    • YouTube
    • TikTok
    • WhatsApp
    • Twitter
    • Instagram
    Latest Reviews
    AI Tutorials

    Quantization from the ground up

    AI Tools

    David Sacks is done as AI czar — here’s what he’s doing instead

    AI Reviews

    Judge sides with Anthropic to temporarily block the Pentagon’s ban

    Subscribe to Updates

    Get the latest tech news from FooBar about tech, design and biz.

    Most Popular

    Text Watermarking in Python: Catch Whoever Copies Your Writing

    0 Views

    The Fairphone 6 Plus is the midrange phone we desperately needed

    0 Views

    German company becomes first in Europe to launch fully commercial orbital rocket

    0 Views
    Our Picks

    Quantization from the ground up

    David Sacks is done as AI czar — here’s what he’s doing instead

    Judge sides with Anthropic to temporarily block the Pentagon’s ban

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    Facebook X (Twitter) Instagram Pinterest
    • About Us
    • Contact Us
    • Terms & Conditions
    • Privacy Policy
    • Disclaimer

    © 2026 ainewstoday.co. All rights reserved. Designed by DD.

    Type above and press Enter to search. Press Esc to cancel.