An engineer's field guide · SynthID Text · Google DeepMind

The watermark you can't see
until you have the key

SynthID marks AI-generated text by nudging which tokens get sampled — no metadata, no hidden characters, no changes after the fact. The signal lives in the statistics of the word choices themselves. This page walks through the full mechanism, the detection math, and where it breaks.

← flip this to see what the detector sees

Sample A — generated with the watermark

Sample B — ordinary human-written text

Simulated, but honestly: each highlight is a real pseudorandom bit (a g-value) computed in your browser by hashing the token, its preceding context, and a secret key — exactly the recomputation a SynthID detector performs. Watermarked text skews toward g = 1 (violet). Unmarked text lands near a 50/50 coin flip. By the end of this page, every part of that sentence will make sense.

00

The problem: provenance without a database

Say you run a platform and want to know whether a block of text came from an LLM. Your classic-software instincts suggest a few designs, and all of them have problems:

Store everything and diff. Log every output your model ever produced and check submissions against the log. This fails on privacy, on scale, and on the first trivial edit.

Attach metadata. Signatures, C2PA-style manifests, hidden Unicode. Text is the worst medium for this — it survives being retyped, screenshotted, copy-pasted through a plain-text field. Any out-of-band channel gets stripped by the most casual laundering imaginable.

Train a classifier. "Detect AI-ness" post hoc from style. These detectors have notoriously poor precision, degrade as models improve, and produce false accusations — the failure mode that burned early AI-text detectors in schools.

SynthID takes a fourth route: change the generator, not the artifact. While the model is choosing each token, bias the choice using a keyed pseudorandom function. The bias is statistically invisible in any single word but accumulates across a passage into a signal that anyone holding the key can test for. It's a watermark in the information-theoretic sense: embedded in the content's own entropy, so it survives copy-paste by construction.

Intuition pump · Monopoly with a book of π

The best analogy for this comes from Anthropic's write-up of their own adoption of this technique. Imagine a Monopoly game where, instead of rolling dice, the players secretly agree to take their "rolls" from the digits of π, starting at some randomly chosen offset deep in the expansion. Nothing about the game changes — a run of digits from the middle of π is statistically indistinguishable from honest rolls, and the outcome is exactly as random as before. But afterward, anyone who knows π (and the offset scheme) can read the move log and work out that this game almost certainly wasn't played with dice. The game is watermarked — not in any object, but in the sequence of choices itself.

SynthID is exactly this, applied to token sampling: the die is the sampler's RNG, the book of π is the keyed PRF, and the move log is the text. Every mechanism on this page is machinery for making that swap precise, quality-neutral, and testable.

Framing for engineers

In systems terms: a covert channel in the sampler. An LLM's sampling step consumes randomness; SynthID replaces some of that randomness with the output of a keyed PRF. Detection is then a hypothesis test: "does this text's randomness correlate with my key?"

This mechanism was published by Dathathri et al. in Nature (October 2024), has been live in the Gemini app since 2024, and the text implementation is open source (also shipped inside Hugging Face Transformers). It's also no longer just a Google thing: the EU AI Act's transparency rules now require providers serving the EU to mark AI-generated content, and Anthropic announced in August 2026 that future Claude models will carry a watermark based on the same SynthID-Text approach — with other signatories to the same Code of Practice implementing their own. The scheme below is on its way to being industry plumbing. Everything that follows tracks the paper.

01

Prerequisite: an LLM is a distribution, not a string

The one piece of ML background you need. An LLM doesn't emit text; it emits a probability distribution over its vocabulary (~250k tokens for Gemini-class models), given everything generated so far. A separate, dumb loop — the sampler — draws from that distribution, appends the pick, and calls the model again:

The vanilla generation loop
while not done:
    probs = model(tokens)          # p(next_token | context) over the whole vocab
    next_tok = sample(probs)       # draw one token — THIS is where randomness enters
    tokens.append(next_tok)

For a prompt like "My favourite tropical fruits are mango and", the distribution might put 22% on bananas, 17% on papayas, and a rounding error on airplanes. Crucially, many next-token choices are genuinely open — several continuations are all fine. That slack, the entropy of the distribution, is the raw material the watermark is carved from. A sentence like "the hike back was long and exhausting" vs. "…and grueling" reads identically either way — the choice between them is settled by a random draw, and it's precisely these consequence-free draws, hundreds of them per response, that the watermark rides on. It never touches the moments where one answer is simply correct.

Two consequences worth flagging now, because they become the limitations in section 06:

— If the distribution is nearly deterministic (the model is 99.9% sure the next token after "The capital of France is" is Paris), there is no slack to embed anything in.

— The watermark must be inserted at sampling time. You cannot watermark text that already exists, and a model whose sampler you don't control can't be marked this way.

02

g-values: a keyed fingerprint for every candidate token

Here's the cryptographic heart of the scheme, and it will feel familiar if you've ever built anything with HMACs. Define a function g that maps (watermarking key, recent context, candidate token, layer index) to a pseudorandom bit:

The random seed generator + g-value function
def g(key, context, candidate, layer):
    # seed from a sliding window of the last H tokens (H = 4 in the paper's config)
    seed = hash_fn(key, context[-4:])
    # one deterministic-but-unpredictable bit per (candidate, layer)
    return prf_bit(seed, candidate, layer)   # ∈ {0, 1}, each ~Bernoulli(0.5)

Properties that make this work:

Deterministic given the key. Anyone holding the key can recompute every g-value from the text alone. That's the whole basis of detection.

Uniform without the key. To anyone else, g-values are indistinguishable from fair coin flips. Human text, or text from an unwatermarked model, averages g ≈ 0.5 — which is exactly what Sample B in the hero shows.

Context-windowed, not position-indexed. The seed depends on the previous H = 4 tokens, not on absolute position. This is a deliberate robustness decision: if someone deletes a sentence, every token whose 4-token window survived intact still scores correctly. A position-indexed scheme would desynchronize after the first edit — the same reason network protocols prefer self-synchronizing framing to absolute offsets.

Layered. There isn't one g-value per token but m of them (think of m independent hash functions; the deployed configuration uses on the order of m = 30 layers). More layers means more watermark bits per token, which means confident detection from shorter text.

Intuition pump · The secret paint job

Picture the key as secretly painting the entire vocabulary two colors — half violet (g = 1), half gray (g = 0) — and then repainting it from scratch at every position, because the context window changed and with it the seed. A watermarked model is a writer who, whenever several words would do equally well, leans slightly violet under whatever the current paint job happens to be. No word is permanently "an AI word" — overcast might be violet at this position and gray two sentences later — which is exactly why no reader, and no keyless classifier, can ever spot the pattern. The detector, holding the key, can reconstruct every paint job after the fact and simply counts how suspiciously violet the author's picks were. This is literally what the lamp at the top of the page renders: flip it on and you're seeing the key's paint job over the text, one bit per token.

The plan

Bias generation so emitted tokens have g-values that skew toward 1. Then detection is just: recompute the g-values, take the mean, and ask how many standard deviations it sits above 0.5. The remaining question — the paper's actual contribution — is how to bias sampling without wrecking text quality.

03

Tournament sampling: bias without distortion

The naive way to bias sampling is to bump the logits of tokens where g = 1 (this is roughly the earlier "green list" scheme from Kirchenbauer et al., 2023). It works, but it distorts: it makes the model systematically prefer words it otherwise wouldn't, and at strong settings the quality cost is measurable. SynthID's replacement is called Tournament sampling, and it's a genuinely pretty algorithm:

1. Draw not one but 2m candidate tokens from the model's distribution, independently, with replacement. (With m = 30 that's conceptual, not literal — see the implementation note below.)

2. Run a single-elimination bracket with m rounds. In round ℓ, pair the survivors up; in each match, the token with the higher g-value for layer ℓ wins. Ties (both 0 or both 1) are broken by a fair coin.

3. Emit the champion.

Tournament sampling (illustrative form)
def tournament_sample(probs, key, context, m):
    candidates = [sample(probs) for _ in range(2**m)]   # all drawn from the REAL distribution
    for layer in range(m):
        survivors = []
        for a, b in pairs(candidates):
            ga, gb = g(key, context, a, layer), g(key, context, b, layer)
            if   ga > gb: survivors.append(a)
            elif gb > ga: survivors.append(b)
            else:         survivors.append(coin_flip(a, b))
        candidates = survivors
    return candidates[0]
Intuition pump · A shortlist and a secret tiebreaker

Think of hiring from a stack of applications. The tournament never recruits anyone who didn't apply — every candidate was drawn from the model's own distribution, in proportion to how much the model liked them. All the key gets to do is break ties among the roughly-equally-qualified. Where the model has a strong favorite, that favorite floods the candidate pool and wins regardless; where the model is torn between five good options, the secret preference quietly settles it. The bias is spent exclusively where the model was indifferent, which is why the reader can't feel it.

Why this construction is clever:

Every candidate came from the model's own distribution. The tournament never invents a preference for a token the model wouldn't plausibly say — it only arbitrates among tokens the model already proposed. If the model puts 99.9% of its mass on Paris, all 2m candidates are Paris and the tournament changes nothing.

The winner skews toward high g-values. Each round filters for the layer's bit, so the champion's g-vector is biased toward 1s across all m layers. That's the watermark.

It's provably non-distortionary on average. The paper shows that, averaged over keys/seeds, the distribution of the emitted token matches the model's original distribution (single-token non-distortion), and a companion trick — repeated-context masking, which skips watermarking whenever the current 4-token window has been seen before — prevents the biases from compounding across a response into repetitive or degraded text.

Implementation note

Nobody materializes 230 samples. Since candidates are i.i.d. draws from a known distribution over a finite vocabulary, each tournament round's effect can be computed as a closed-form update on the probability vector itself — m cheap vectorized passes, one per layer. The open-source release does exactly this; watermarking adds negligible latency, which is what made it deployable in production Gemini serving.

Below is a live m = 3 tournament (8 candidates) over a toy distribution. The g-values are real: hashed in your browser from (key, context, token, layer). Run it a few times, then run the batch — watch the emitted tokens' mean g-value pull away from 0.5 while the which-words-get-used frequencies stay anchored to the model's distribution.

Demo · Tournament sampling, one token at a time
Context: "My favourite tropical fruits are mango and" — the model's next-token distribution. Each run draws a fresh random seed, standing in for a fresh 4-token context window at a new position in the text:
tokens emitted
0
mean g of emitted
expected if unmarked
0.500
bananas frequency · true 22%

With the watermark off, the bracket is skipped and one token is drawn directly — mean g hovers around 0.5. With it on, mean g climbs to ~0.71, yet over the batch bananas still lands at its true 22% and even airplanes keeps its 3%. That's non-distortion in action: at any single position the tournament reshuffles among the model's own candidates, but averaged over seeds (i.e., positions in real text) the output distribution is unchanged — only the correlation with the key remains.

Gears check: where does each layer's bias actually come from?

The bracket above shows tokens advancing. To see the mechanism, zoom in one level: every candidate carries an m-bit vector, and each round is allowed to look at exactly one column of it. One pairwise match on layer ℓ takes that column's bit from a 50/50 coin to a 75/25 coin — the winner has g = 1 in three of the four possible matchups (1v0, 0v1, 1v1), losing out only when both contestants drew 0. And because the layers are independent hash functions, a round that selects on column ℓ tells you nothing about the other columns: bias banked in earlier rounds is frozen, bias in later columns stays at 0.5 until their turn. That's the whole trick — the champion exits with every one of its m bits independently nudged to ~0.75, and it's why the bracket needs 2m entrants: m rounds of halving, one match's worth of selection pressure per layer.

Intuition pump · Thirty weak watermarks in a trench coat

One layer alone is a hopelessly faint watermark — a coin nudged from 50% to 75%, needing thousands of tokens before you'd trust it. The layers construction just runs m of these faint watermarks in parallel over the same tokens, each with its own hash function, and pools the evidence at detection time. Same trick as a Bloom filter's k independent hash functions, or checksumming with several independent parity bits: each channel is weak and cheap, correlated with nothing but the key, and the aggregate is strong. The tournament is merely the scheduler that lets all m of them take their one nudge at a single sampling decision without trampling each other.

Step through it below. Watch the active column jump toward 0.75 during its round. (With only 8 candidates the numbers are noisy — banked columns can jitter from small-pool luck — so run the batch afterward to see the clean picture: all three layers equally biased, none disturbed by the others' rounds.)

Demo · One column per round: how layers mint bias
Eight candidates, each with a real 3-bit g-vector (hashed from key + seed + token). Violet = 1, gray = 0. The stats row tracks P(g = 1) in the surviving pool.
Deal a fresh pool of candidates to begin.
04

Detection: a hypothesis test, not a vibe check

Detection needs no model, no GPU, and no record of the original generation. Given a suspect text and the key:

The detector (frequentist form)
def detect(text, key, m, H=4):
    toks = tokenize(text)
    gs = []
    for i, tok in enumerate(toks):
        ctx = toks[max(0, i-H):i]
        for layer in range(m):
            gs.append(g(key, ctx, tok, layer))       # recompute every watermark bit

    mean_g = sum(gs) / len(gs)
    # H0 (not watermarked): each g ~ Bernoulli(0.5)  →  mean_g ≈ 0.5, σ = 0.5/√N
    z = (mean_g - 0.5) / (0.5 / len(gs)**0.5)
    return z          # e.g. z > 4  ⇒  watermarked, p < 3×10⁻⁵
Intuition pump · The suspicious coin log

Someone hands you a log of 12,000 coin flips and swears the coin was fair. It came up heads 55% of the time. You don't need to inspect the coin, watch a replay, or understand who flipped it — the log alone convicts, because a fair coin lands within a fraction of a point of 50% over that many flips. That's the entire detector: the g-values are the flips, the key is what lets you read heads from tails, and "watermarked" is just "this coin log is rigged." It's also the π-Monopoly check from the top of the page — reading the move log against the book after the game is over.

The null hypothesis is beautiful in its simplicity: text not generated with this key produces i.i.d. fair-coin g-values. So the mean over N = tokens × m bits concentrates hard around 0.5, and you can set a z-threshold to hit whatever false-positive rate your application demands. Note what m buys here: every layer contributes an independent observation per token, so confidence grows like √(tokens × m) — m = 30 layers reach the same z-score as a single layer would on a text roughly 30× longer. Layers are how the scheme gets short-text detection. False accusations — the thing that kills AI-text detectors in practice — become a tunable statistical parameter rather than a model's opinion. (The production system actually uses a learned Bayesian detector that weights each g-value by how much entropy its position had, squeezing more power out of short texts, but the frequentist version above is the right mental model.)

Consequences of the key

Detection is gated on the key. Only Google can check for Gemini's watermark (surfaced via "ask Gemini if this was made by Google AI" and the SynthID Detector portal for journalists). There is no public oracle — deliberately, since an open detector would double as a training signal for scrubbing.

It's per-vendor, not universal. A SynthID check on text from an unwatermarked model, or a different vendor's model, correctly returns "no signal" — it cannot say "this is human." Absence of a watermark is not evidence of humanity.

Anyone can run their own. The open-source release lets you watermark your own model's sampler with your own keys and run your own detector — the scheme is infrastructure, not a Google-only capability.

05

How much signal survives? A back-of-envelope lab

Because detection is a mean of noisy bits, its power follows textbook statistics: the z-score grows with √(number of intact watermark bits) and linearly with per-token bias, which itself depends on entropy. Edits destroy bits two ways — a replaced token loses its own g-values and poisons the context windows of the next H tokens. Play with the three levers:

Demo · The robustness lab
An illustrative model of detection confidence (z-score) as text length, editing, and entropy vary. Shapes and crossover points are faithful to the mechanism; exact numbers depend on configuration.
z = — · detected

Read the curve left to right as an attacker paraphrasing progressively more of the text. Notes: doubling length only buys √2 more confidence; low-entropy content starts weak even unedited; and the curve's fast early drop reflects context-window poisoning — each edited token damages its neighbors' windows too.

06

Threat model: what breaks it, honestly

The Nature paper and DeepMind's own materials are candid that this is a transparency tool, not a security boundary. It raises the cost of passing off AI text undetected; it does not make it impossible. The failure modes, ranked:

ScenarioEffect on detectionWhy
Copy-paste, reformatting Survives The watermark is the token statistics themselves. There's nothing to strip.
Light edits, cropping Mostly survives Sliding-window seeding is self-resynchronizing; intact regions keep scoring. A cropped excerpt just behaves like a shorter text.
Low-entropy tasks Weak from the start Once the model has written "Isaac Newton's most famous work was the", the next tokens are forced — a nudge toward any other continuation would make the text wrong, so none is applied. Factual recall, arithmetic, exact code, and "respond with exactly X" prompts are wall-to-wall forced moves: no entropy in, no watermark out. Short replies compound this — too few bits to test either way.
Model edits human text Little to attach to Ask a watermarked model to fix grammar in your draft and nearly every word in the output is still yours — the watermark only lives in tokens the model chose, so a handful of corrections may be too few bits to register. The flip side of "the more the model writes, the more decisions it makes." (Note the asymmetry: a translation produced by the model is fully watermarked, since it chose every word — distinct from the scrubbing attack below.)
Heavy paraphrase / re-translation Largely destroyed Taking already-watermarked text and rewriting most tokens — especially via another LLM, or round-tripping through another language with a different tool — replaces the very statistics that carry the signal. This is the canonical scrubbing attack, and the paper doesn't claim to withstand it.
Generate elsewhere Out of scope A determined actor just uses an open-weights model with a vanilla sampler. Watermarking only covers cooperating generators — its value is ecosystem-level (default-on in mass-market tools), not adversary-proof.
Deployment caveats

Key secrecy is load-bearing. With the key, forging watermarked text (framing) or optimally scrubbing it becomes trivial — this is a symmetric-key design, with the key-management burdens that implies. And a "not detected" result means only that: unmarked, edited, other-vendor, or human are all indistinguishable outcomes.

Does it hurt output quality?

The strongest evidence in the paper is operational, and it's the kind of experiment infra engineers will appreciate: a live A/B across ~20 million Gemini responses, watermarked vs. not, measuring user thumbs-up/thumbs-down rates. No statistically meaningful difference. That result — quality preserved at production scale, detection still reliable — is the practical claim that distinguishes Tournament sampling from earlier logit-bumping schemes.

07

Sidebar: images, audio, video

"SynthID" is one brand over several unrelated mechanisms — only the text scheme works by biasing a sampler. For completeness:

Images & video

A learned encoder network embeds an imperceptible pattern directly into pixel values (per-frame for video); a paired decoder network detects it. Trained to survive crops, filters, re-compression, and frame-rate changes. Used by Imagen, Veo, and Gemini's image output.

Audio

The waveform is converted to a spectrogram, a watermark is embedded there, and it's converted back — inaudible, and robust to MP3 compression, added noise, and speed changes. Used by Lyria and NotebookLM audio.

Text

Everything on this page: keyed g-values + Tournament sampling at generation time, statistical hypothesis test at detection time. The only modality where the watermark is carried by choices rather than embedded in a continuous signal.

Verification is being productized the same way across all of them: upload content to Gemini and ask whether Google AI made it, or use the SynthID Detector portal (in testing with journalists and media organizations).