How LLM Text Watermarks Work

How LLM Text Watermarks Work

How LLM text watermarks actually work, why the EU forced them into production in 2026, what each vendor shipped, and what it means if you build on these APIs.


For two years the internet has been chasing the wrong watermark. In April 2025 people found narrow no-break spaces (U+202F) in ChatGPT output and a cottage industry of "watermark removers" sprang up. That was never a watermark. OpenAI said it was a quirk of reinforcement learning, and it disappeared within three days [1].

The real watermarks arrived in August and October 2026, pushed by Article 50 of the EU AI Act. Claude now watermarks every piece of text it generates, worldwide, on every surface including the API and Bedrock [2]. OpenAI watermarks ChatGPT and Codex output in the EU and lets API customers opt in anywhere [3]. Gemini has done it since 2024 [4].

None of these put anything in the characters. They change which words get picked. A unicode scanner will find nothing because there is nothing there to find. This post explains the mechanism with worked numbers, cites the papers behind it, and ends with what it means for teams building products on top of these models.

1. Why now: Article 50 of the EU AI Act

Regulation (EU) 2024/1689, the AI Act, has a transparency chapter that applied from 2 August 2026 [5]. Two paragraphs matter here.

Article 50(2) is for providers. If your AI system generates synthetic audio, image, video or text, you must ensure the output is marked in a machine-readable format and is detectable as artificially generated. The techniques must be effective, interoperable, robust and reliable "as far as technically feasible". Text is explicitly in scope.

Article 50(4) is for deployers. If you publish a deepfake, you disclose it. If you publish AI-generated text to inform the public on a matter of public interest, you disclose it, unless a human has reviewed it and someone holds editorial responsibility.

The Act says what, not how. The how came in three documents during summer 2026:

  • 10 June 2026: the Commission published the final Code of Practice on Transparency of AI-Generated Content [6]. It is voluntary, but signing it gives legal certainty. Around 190 organisations signed by end of July, including Anthropic, Google, Meta, Microsoft, Mistral and OpenAI [7].
  • 20 July 2026: the Commission published its Article 50 guidelines and Q&A [8].
  • 8 July 2026: the Digital Omnibus on AI, Regulation (EU) 2026/1744, added a transition. Systems already on the market before 2 August 2026 have until 2 December 2026 to meet the marking and detection requirement [9]. New systems had to comply on day one.

The Code is where the engineering requirements live. For providers it sets four commitments: mark the content, make the marks detectable, meet quality bars for the marking solution, and test and verify. It expects a layered approach: signed metadata (C2PA), an imperceptible watermark, and fingerprinting or logging as a fallback. For free-form text it accepts a watermark alone, because you cannot attach metadata to a paragraph someone pastes into an email. Text shorter than 200 tokens is exempt. Providers may restrict access to a text detector to vetted parties, within limits. And signatories must not market tools designed to circumvent marks [6][10].

Fines for Article 50 breaches run up to €15 million or 3% of global turnover, whichever is higher (Article 99(4)).

Outside the EU: California's AI Transparency Act (SB 942, amended by AB 853) became operative on the same date, 2 August 2026, on purpose. It requires large providers to add latent disclosures and offer a detection tool, but covers image, video and audio, not text [11]. China's labelling measures have required explicit and implicit (metadata) labels on AI content since 1 September 2025.

So: a hard deadline, a compliance document that names watermarking as the method for text, and two hundred companies signing. That is why your Claude output now carries a mark.

2. The thing people thought was a watermark

Before the real mechanism, the fake one. In April 2025 the team at Rumi noticed that o3 and o4-mini output contained U+202F (narrow no-break space) where a normal space should be [1]. It looks identical on screen. Their argument was reasonable: humans never type that character, so its presence is near-conclusive evidence of ChatGPT.

Two days later OpenAI told them it was not a watermark, just an artefact of large-scale RL training. By 23 April it was gone.

The same category includes zero-width spaces (U+200B), zero-width joiners (U+200C, U+200D), byte-order marks (U+FEFF), curly quotes, and em dashes. They are typographic fingerprints. Some are model habits, some come from copying out of a rich-text editor. All of them are detectable and removable with a regex:

import re
import unicodedata

SUSPECT = re.compile(r"[\u00A0\u2000-\u200F\u2028\u2029\u202F\u205F\u2060\uFEFF]")

def scan(text):
    return [(m.start(), f"U+{ord(m.group()):04X}", unicodedata.name(m.group(), "?"))
            for m in SUSPECT.finditer(text)]

def clean(text):
    # spaces become a plain space, format characters are dropped
    return SUSPECT.sub(lambda m: " " if unicodedata.category(m.group()) == "Zs" else "", text)

Run scan() on April 2025 ChatGPT output and you get a list of U+202F hits. Run it on Claude output today and you get an empty list. Run clean() on watermarked text and the detector score afterwards is essentially unchanged, because the watermark was never in the whitespace. Section 5 explains why.

3. How a real text watermark works

Every statistical text watermark in production rests on one fact about language models: at most positions, the model is choosing among several good next words. A watermark is a rule, driven by a secret key, that tips those near-ties in a consistent direction. Humans do not know the key, so their writing does not follow the rule. Over a few hundred words, the tilt becomes statistically obvious to anyone who holds the key.

Three families matter. Each production system is a descendant of one or two of them.

3.1 Red-green lists (Kirchenbauer et al., 2023)

The scheme that started the field is from Kirchenbauer, Geiping, Wen, Katz, Miers and Goldstein, "A Watermark for Large Language Models" (ICML 2023) [12]. It is simple enough to work through by hand.

At each generation step:

  1. Take the previous token and hash it with the secret key to seed a random number generator.
  2. Use that generator to split the vocabulary into a "green" list (a fraction γ, typically 0.5) and a "red" list.
  3. Add a constant δ (typically 2.0) to the logit of every green token.
  4. Sample as normal.

Worked example. The prompt so far is "Please send the report by". Suppose the model's raw next-token distribution is:

token p (raw) logit (log p)
Friday 0.40 −0.92
Monday 0.25 −1.39
tomorrow 0.15 −1.90
noon 0.10 −2.30
EOD 0.10 −2.30

The key and the previous token "by" seed the generator, which marks Monday, tomorrow, EOD green and Friday, noon red. Add δ = 2 to the green logits and renormalise:

token list logit after p (watermarked)
Friday red −0.92 0.10
Monday green +0.61 0.44
tomorrow green +0.10 0.26
noon red −2.30 0.02
EOD green −0.30 0.18

Green mass went from 0.50 to 0.88. The text is still fluent. "Please send the report by Monday" is a perfectly good sentence. Nothing visible changed. What changed is the odds.

Detection needs the key and nothing else. For each token in the suspect text, recompute the green list from the previous token and count how many tokens landed green. Human text lands green about γ of the time by chance. The test statistic is a z-score:

z = (green_count − γT) / √(T · γ · (1 − γ))

For T = 200 tokens and γ = 0.5, a human writer is expected to hit 100 green with a standard deviation of about 7. Watermarked text at 85% green hits 170, so z ≈ 9.9. Even a weakly watermarked passage at 130 green gives z ≈ 4.2, which corresponds to a false positive rate around 1 in 70,000. The authors use z = 4 as a threshold.

Here is the detector in a few lines, assuming you have the model's tokenizer and the key:

import math, hashlib, random

def is_green(prev_token_id, token_id, key, gamma, vocab_size):
    seed = int(hashlib.sha256(f"{key}:{prev_token_id}".encode()).hexdigest(), 16)
    rng = random.Random(seed)
    perm = list(range(vocab_size))
    rng.shuffle(perm)
    return perm.index(token_id) < gamma * vocab_size   # toy; real code uses a hashed partition

def z_score(token_ids, key, gamma, vocab_size):
    T = len(token_ids) - 1
    green = sum(is_green(a, b, key, gamma, vocab_size)
                for a, b in zip(token_ids, token_ids[1:]))
    return (green - gamma * T) / math.sqrt(T * gamma * (1 - gamma))

Note what this does not use: the model. The detector is cheap, runs anywhere, and only needs the key. That is why keys stay private.

Where it fails: low entropy. Now the prompt is "The capital of France is". The model gives Paris a probability of 0.995. Even if Paris is red and the runner-up is green, adding 2 to the runner-up's logit moves its probability from 0.002 to roughly 0.015. Paris still wins with 98% probability. That token carries almost no watermark signal. Code, JSON, SQL, boilerplate and quotations are mostly like this, which is why detection on code is much weaker and why later work (SWEET [13], EWD [14]) weights or skips low-entropy tokens. Keep this in mind when you read vendor detection numbers: they are measured on prose.

3.2 Distortion-free sampling (Aaronson 2022, Kuditipudi et al. 2023, Christ et al. 2023)

Red-green lists change the distribution. Over many generations from the same prompt, a watermarked model is measurably different from the original. Scott Aaronson, working at OpenAI, proposed a different idea in late 2022 [15]: do not change the probabilities, change the dice.

For each step, the key and recent context produce a uniform random number r_i in [0,1] for every vocabulary item i. Instead of sampling, pick the token that maximises r_i^(1/p_i) (the Gumbel-max trick). For a single draw this is exactly a sample from the model's distribution, so no single output is distorted. But the chosen token always has a suspiciously high r_i. The detector recomputes the r values from the key and sums log(1/(1 − r_chosen)) across the text. Human text gives an average around 1 per token; watermarked text gives more.

Kuditipudi, Thickstun, Hashimoto and Liang formalised this as "distortion-free" watermarking and made detection robust to insertions and deletions by aligning the key sequence to the text with edit distance [16]. Christ, Gunn and Zamir proved that watermarks can be cryptographically undetectable without the key, meaning no test without the key can tell watermarked and unwatermarked output apart [17]. These are the theoretical foundations the production systems cite.

3.3 Tournament sampling: SynthID-Text (Google DeepMind, Nature 2024)

Google's SynthID-Text is the first one that ran at scale. The paper is Dathathri et al., "Scalable watermarking for identifying large language model outputs", Nature 634, 818–823 (October 2024) [4]. The code is open source in Hugging Face Transformers since v4.46 [18].

Instead of one green list, it uses m layers of pseudo-random scores. At each step:

  1. Hash the key with the last few tokens (the context window) to seed the layer functions g₁ … g_m. Each g_ℓ(token) is a fair coin: 0 or 1 with probability 0.5.
  2. Sample 2^m candidate tokens from the model's distribution, with replacement.
  3. Run a knockout tournament. In layer 1, pair the candidates up; in each pair, the one with the higher g₁ wins (ties broken at random). In layer 2, the winners pair up and compete on g₂. Continue until one remains.
  4. Output the winner.

Worked example with m = 2, same prompt as before. Sample four candidates from the raw distribution: Friday, Friday, Monday, tomorrow (Friday twice because it had 40% probability). The key and context give:

candidate g₁ g₂
Friday 0 1
Monday 1 0
tomorrow 1 1

Layer 1: Friday vs Friday → Friday (identical). Monday vs tomorrow → both have g₁ = 1, coin flip, say Monday. Layer 2: Friday (g₂ = 1) vs Monday (g₂ = 0) → Friday wins.

The output is the same word the plain model would most likely have produced. But look at what the tournament selects for: the winner tends to have high g-values across the layers. Averaged over hundreds of tokens, the mean g-value of watermarked text drifts above 0.5, while human text sits at 0.5 because the coins are fair and nobody was selecting on them.

Detection recomputes g₁ … g_m for every token from the key and the preceding context, averages them, and tests the mean against 0.5. The paper also trains a small Bayesian detector that outperforms the plain mean, and a 2026 analysis by Omidi, Dong and Wang proves why: the mean score is vulnerable to a "layer inflation" attack, the Bayesian score is not, and Bernoulli(0.5) is the optimal coin [19].

Two properties made this deployable. First, with Bernoulli g-values and tournament sampling, the expected distribution of a single generation equals the model's original distribution (the paper calls this non-distortionary). Second, "repeated context masking" skips the watermark at any step whose context window has already been seen, so repeated prompts do not collapse onto identical answers. Google ran it live on roughly 20 million Gemini responses and found no measurable difference in user ratings [4].

3.4 Entropy-calibrated: textGrain (OpenAI, October 2026)

OpenAI's scheme is described in a 20-page technical report published with the 5 October 2026 announcement, with co-authors from Penn and Yale [3][20]. It combines the randomness of red-green lists with the unbiasedness of Gumbel-max, and adds an explicit entropy budget: the watermark spends its bias where the model is undecided and leaves confident tokens alone. The selection is set up as an optimal transport problem with Gumbel-derived costs and a KL penalty against distorting the model's distribution. The detector needs only the text and the key; it does not need to know what budget was used at generation time.

OpenAI's own numbers, at a 1% false positive target on roughly 400-token passages [3][21]:

condition detection rate
unedited ~92%
10% of words swapped for synonyms 66%
25% of words swapped 17%
~200 tokens, unedited ~80%

An October 2026 analysis on arXiv shows the entropy calibration comes at a cost: textGrain's detectable region after edits is strictly smaller than Gumbel-max's [20]. That is a trade OpenAI chose: less distortion and less repetition, in exchange for a weaker signal.

4. What each vendor actually shipped

Anthropic (Claude) OpenAI (ChatGPT / API) Google (Gemini)
Text watermark Yes, model-level textGrain SynthID-Text
Where it's on Worldwide, every surface: API, apps, Claude Code, Cowork, Tag, AWS Bedrock, Google Cloud, Microsoft Foundry [2] ChatGPT and Codex, EU only. API: opt-in, off by default, globally [3] Gemini app. API status is unclear; Google's own developer forum gives contradictory answers [22]
Which models Everything launched after 2 Aug 2026 (Opus 5/5.5, Sonnet 5/5.5, Haiku 5.5, Fable, Mythos). Backported to Opus 4.7, 4.8 and Sonnet 4.6. Not on 4.5 or Haiku 4.5 [2] "Select models" via API; all plans in ChatGPT EU Gemini models in the app
Detector access Private preview: regulators, media, researchers, fact-checkers, EU civil society, and enterprises checking their own outputs. Request form [2] Approved researchers and expert organisations, case by case [3] SynthID Detector portal, waitlisted for text [23]
Files C2PA Content Credentials on generated PNG, JPEG, SVG; public checker at claude.com/check-content [2] C2PA on images (existing) SynthID on images, audio, video
Algorithm published No. Press reports say it is SynthID-derived; Anthropic has not confirmed [24] Yes, technical report Yes, Nature paper and open code

Three details in the Anthropic page are worth reading twice.

First, "watermarking will be applied at the model level, which means it will be present no matter which Claude product or surface the text comes from" [2]. There is no API parameter to disable it. If you build on Claude, your users' output is marked.

Second, the footnote on Sonnet 4.6: outputs "may not reliably carry the text watermark when temperature, top_p, or top_k is set to a non-default value" [2]. That is exactly what you would expect from a watermark that lives in the sampling step, as every scheme in Section 3 does. The newer models carry no such caveat, which suggests the implementation moved somewhere less fragile, but Anthropic has not said where.

Third, the two-sided limitation that every vendor now repeats: a detected mark means Claude processed the text, not that Claude wrote the ideas (you may have asked it to proofread your own draft), and a missing mark proves nothing, because the model may be too old, the text too short, too edited, translated, or produced on a surface without marking [2][3].

The known hole is open weights. Meta and Mistral signed the Code, but anyone who downloads Llama or Mistral weights and runs them locally is not obliged to watermark anything, and most do not.

5. So can you just strip it with unicode detection?

No. Here is the reasoning laid out.

The unicode cleaner in Section 2 changes spacing characters and removes format characters. It never touches a word. The watermark in Section 3 is encoded entirely in which words were chosen. After clean(), the detector tokenises the same words, recomputes the same g-values or green lists from the same key and the same preceding words, and gets the same score. The only thing that can move the score at the margins is tokenisation noise where a NNBSP became a space, and every production detector is built to tolerate far more than that (SynthID is documented as robust to cropping and modifying a few words [18]).

In the opposite direction, people have tried inserting homoglyphs and zero-width characters to break detectors by scrambling tokenisation. Kirchenbauer et al. discuss this in the original paper and the answer is canonicalisation: normalise the unicode before detecting [12]. It is a one-line fix on the detector side.

What does degrade a statistical watermark is changing the words, and the research record on that is consistent:

  • Paraphrase with another model. Krishna et al. (NeurIPS 2023) built DIPPER, a paraphraser that dropped a red-green watermark's detection from 100% to roughly 80% at 1% FPR, and cut other detectors far more [25]. Sadasivan et al. showed recursive paraphrasing pushes detection toward chance [26].
  • Human edits. OpenAI's own figures above: 25% of words swapped takes detection to 17% [3].
  • Length recovers it. Kirchenbauer et al. (2023b) found that watermarks survive human paraphrase if enough text remains, on the order of several hundred to a thousand tokens, because the surviving tokens still tilt the statistics [27].
  • Translation between languages destroys it, since none of the original tokens survive [2].
  • Watermark stealing. Jovanović, Staab and Vechev showed that for red-green schemes, an attacker who queries the watermarked model enough times can approximate the green rule well enough to both scrub real marks and forge fake ones, for tens of dollars of API spend [28]. Schemes that hash a longer context and keep the key private resist this better, which is one reason vendors are gating their detectors.

None of this is a how-to. The point is the asymmetry: a regex costs nothing and removes nothing; a rewrite that actually removes the signal costs about as much as writing the text yourself, and the Code of Practice bars every signatory from selling you a tool that does it [6].

6. What this means if you build on these models

This is the part we care about at Softmax, because most of our work is Claude and OpenAI models deployed inside clients' products in regulated industries.

Your Claude output is watermarked, whether or not you wanted it. Worldwide, on Bedrock, in Foundry, through the API. There is no toggle. If a client asks whether their document assistant's output is "detectable as AI", the answer since August is yes for any supported model, and you should be able to say which model they are on and point to the Anthropic table [2].

On OpenAI it is your decision. The API is off by default everywhere. If you serve EU users through your own product, you are the deployer, and the Commission guidelines let a deployer rely on the provider's marking where it exists (point 74 of the guidelines [8]). Turning the opt-in on for EU traffic is the cheapest way to inherit compliance. Leaving it off means the marking obligation is yours to solve another way.

You cannot verify it yourself yet. Both detectors are gated. Anthropic lists "enterprises that need to check marks on their own Claude outputs" as eligible, and there is a request form [2]. If a client's compliance file needs evidence, apply now, and until then document reliance on the provider's published statement.

Do not build policy on a negative result. HR, academic integrity, legal review, content moderation: a missing mark is not evidence of human authorship. Any product that implies otherwise is making a claim the vendors themselves refuse to make.

Low-entropy outputs carry weak signal. Structured extraction, JSON, SQL, templated letters, short answers under 200 tokens. These are most of what production AI systems produce and they are exactly where detection is least reliable. Do not expect a watermark detector to flag a 40-token field extraction.

Article 50(4) is yours, not the provider's. If your product publishes AI-written text on matters of public interest (municipal notices, public health comms, news-like summaries), the deployer must disclose it, and the provider's invisible watermark does not satisfy that. The EU has published three icons for this purpose [29]. Human review with editorial responsibility exempts you, which for most B2B workflows is already the case.

Files too. Claude attaches C2PA credentials to generated images and SVGs. If your pipeline re-saves or converts files, the credential is gone, and that is fine, but know that it was there.

And do not bother stripping anything. The regex finds nothing, the rewrite costs more than the content, and your clients are better served by a line in the product documentation that says what the model does.


References

  1. Rumi, "New ChatGPT Models Seem to Leave Watermarks on Text", 20 April 2025, with OpenAI's response and resolution updates. https://www.rumidocs.com/newsroom/new-chatgpt-models-seem-to-leave-watermarks-on-text
  2. Anthropic, "How Claude marks AI-generated content", Claude Help Center. https://support.claude.com/en/articles/16266773-how-claude-marks-ai-generated-content
  3. OpenAI, "Our approach to EU text provenance rules", 5 October 2026. https://openai.com/index/eu-text-provenance/
  4. Dathathri, S. et al., "Scalable watermarking for identifying large language model outputs", Nature 634, 818–823 (2024). https://www.nature.com/articles/s41586-024-08025-4
  5. Regulation (EU) 2024/1689 (AI Act), Article 50.
  6. European Commission, Code of Practice on Transparency of AI-Generated Content, 10 June 2026. https://digital-strategy.ec.europa.eu/en/policies/code-practice-ai-generated-content
  7. European Commission press release IP/26/1328, 10 June 2026. https://ec.europa.eu/commission/presscorner/detail/en/ip_26_1328
  8. European Commission, Guidelines on transparency obligations under Article 50, C(2026) 5054, 20 July 2026.
  9. Regulation (EU) 2026/1744 of 8 July 2026 (Digital Omnibus on AI), inserting Article 111(4).
  10. Bird & Bird, "Taking the EU AI Act to Practice: The Final Transparency Code of Practice", June 2026. https://www.twobirds.com/en/insights/2026/taking-the-eu-ai-act-to-practice-the-final-transparency-code-of-practice
  11. California SB 942 as amended by AB 853 (Chapter 674, Statutes of 2025), operative 2 August 2026. https://natlawreview.com/article/californias-ongoing-ai-regulation-key-deadlines-arriving-2026-and-beyond
  12. Kirchenbauer, J., Geiping, J., Wen, Y., Katz, J., Miers, I., Goldstein, T., "A Watermark for Large Language Models", ICML 2023. arXiv:2301.10226
  13. Lee, T. et al., "Who Wrote this Code? Watermarking for Code Generation" (SWEET), 2023. arXiv:2305.15060
  14. Lu, Y. et al., "An Entropy-based Text Watermarking Detection Method", ACL 2024. arXiv:2403.13485
  15. Aaronson, S., "My AI Safety Lecture for UT Effective Altruism", November 2022 (the Gumbel-max / exponential-minimum sampling watermark). https://scottaaronson.blog/?p=6823
  16. Kuditipudi, R., Thickstun, J., Hashimoto, T., Liang, P., "Robust Distortion-free Watermarks for Language Models", TMLR 2024. arXiv:2307.15593
  17. Christ, M., Gunn, S., Zamir, O., "Undetectable Watermarks for Language Models", COLT 2024. arXiv:2306.09194
  18. Hugging Face and Google DeepMind, "Introducing SynthID Text", October 2024. https://huggingface.co/blog/synthid-text
  19. Omidi, R., Dong, Y., Wang, B., "On Google's SynthID-Text LLM Watermarking System: Theoretical Analysis and Empirical Validation", 2026. arXiv:2603.03410
  20. "textGrain watermarking is harder to detect: can sum-tests still do it optimally?", October 2026. arXiv:2610.17655 (cites the OpenAI technical report, Li et al. 2026, "textGrain: Entropy-Calibrated Watermarking for Language Model Text")
  21. Cloud Security Alliance research note on EU text watermarking, 9 October 2026, summarising OpenAI's reported detection figures. https://labs.cloudsecurityalliance.org/research/csa-research-note-eu-ai-act-text-watermarking-20261009-csa-s/
  22. Google AI Developers Forum thread, "Does Gemini API text output carry SynthID watermarking?", August 2026. https://discuss.ai.google.dev/t/does-gemini-api-text-output-carry-synthid-watermarking-gemini-2-5-flash-lite-gemini-3-1-flash-lite-eu-ai-act-art-50-2/177241
  23. Google, SynthID Detector portal announcements, I/O 2026.
  24. The Decoder, "OpenAI will watermark ChatGPT text in the EU but makes it optional for API users worldwide", 5 October 2026. https://the-decoder.com/openai-will-watermark-chatgpt-text-in-the-eu-but-makes-it-optional-for-api-users-worldwide/
  25. Krishna, K., Song, Y., Karpinska, M., Wieting, J., Iyyer, M., "Paraphrasing evades detectors of AI-generated text, but retrieval is an effective defense", NeurIPS 2023. arXiv:2303.13408
  26. Sadasivan, V. S. et al., "Can AI-Generated Text be Reliably Detected?", 2023. arXiv:2303.11156
  27. Kirchenbauer, J. et al., "On the Reliability of Watermarks for Large Language Models", ICLR 2024. arXiv:2306.04634
  28. Jovanović, N., Staab, R., Vechev, M., "Watermark Stealing in Large Language Models", ICML 2024. arXiv:2402.19361
  29. European Commission, "EU icons for labelling AI-generated content", Shaping Europe's digital future (digital-strategy.ec.europa.eu).