What Article 50 of the AI Act requires from teams building generative products, and how to implement it without stalling the roadmap.
Note. This post is technical guidance, not legal advice. The exact classification of your system (whether you are a provider, whether an exemption applies) deserves a review with your legal team. What engineering can do is have the system ready and the evidence documented.
Until recently, "marking AI-generated content" sounded like something OpenAI, Google or Anthropic would do inside their models, not something the rest of us had to worry about. That changed on August 2, 2026, when the transparency obligations in Article 50 of the EU AI Act started to apply. And there is a date many teams still don't have on their calendar: December 2, 2026, when the transition period ends for marking content from generative systems that were already on the market before August.
If your product generates text, images, audio or video that people in the EU see, this very likely affects you, even if you never trained a model and everything goes through a third-party API. This post explains what the rule asks for in engineering terms, where the traps are (almost all in the pipeline, not in the model) and what we would do in the month that's left.
This is the third post in our series on best practices for building AI products. The previous one covered locking down your LLM gateway; today we look at marking synthetic output under Article 50 before the December deadline.
1. What Article 50 requires, in four obligations
Article 50 bundles several distinct obligations with different addressees. It's worth separating them, because each one is solved in a different layer of the product:
| Obligation | Who | What to do | From |
|---|---|---|---|
| 50(1) Disclose that people are interacting with AI | Provider | Tell people they are dealing with an AI system (chatbots, agents, avatars), unless it's obvious | Aug 2, 2026 |
| 50(2) Mark generated content | Provider | Machine-readable marks on synthetic text, image, audio and video, and make them detectable | Aug 2, 2026 (new systems) / Dec 2, 2026 (systems on the market before Aug 2) |
| 50(3) Disclose emotion recognition or biometric categorisation | Deployer | Inform exposed people | Aug 2, 2026 |
| 50(4) Label deepfakes and public-interest text | Deployer | A visible or audible label, perceivable without tools | Aug 2, 2026 |
Three details that are easy to miss:
- The transition period only covers 50(2) marking. The AI Omnibus (Regulation (EU) 2026/1744) gave systems already on the market before August 2 until December 2, and only for marking and detection. If your chatbot is both interactive and generative, the "you're talking to an AI" notice should have been there since August.
- No retroactive marking of content generated before August 2. But pre-August text published after that date is in scope.
- Fines for breaching transparency obligations can reach €15 million or 3% of worldwide annual turnover, with proportionality for SMEs. Enforcement is mostly by national market surveillance authorities; the AI Office only acts in specific cases, such as when the same provider offers the general-purpose model and the system built on it.
The Commission has also published two documents that make all this concrete: the Guidelines on Article 50 (adopted July 20, 2026) and the Code of Practice on Transparency of AI-generated Content (final version June 10, 2026), signed by around 190 organisations, including the major model providers. Neither is binding, but the Code is the clearest way to show compliance: non-signatories must justify by other means that their measures are adequate.
2. "But I just call an API": why you are probably a provider
This is the question we hear most from the teams we work with, and the short answer is uncomfortable.
The AI Act defines a provider as whoever develops an AI system (or has it developed) and places it on the market or puts it into service under their own name or trademark. As Bird & Bird explain, calling an API is not the dividing line in itself: what makes you a provider is building a distinct system around the model and offering it under your name, even if only your own staff use it. A branded writing assistant, a report generator for customers or a customer-support agent all fit.
The good news is that the Guidelines allow someone else to do the marking: a provider may rely on the marking solution of the model provider or a third party "to the extent that such solution complies with Article 50(2)". The bad news is the next sentence: that reliance is "without prejudice to the responsibility of the provider of the AI system to demonstrate compliance" (para. 74). The same goes for detection: if you depend on someone else to provide it, you must ensure it complies (para. 78).
In practice that means three things:
- Don't assume your provider marks. General-purpose model providers are only encouraged to mark at model level, not obliged. Check it, per model and per channel.
- Your pipeline can strip the mark even when the model applies it. More on that in section 4.
- You need evidence: which technique you use, why, and how you verified it. The Guidelines and legal analyses stress documenting the technical choice, because that reasoning is your proof.
3. What's out of scope (and what isn't, quite)
Before marking anything, narrow the scope. The Guidelines exclude from 50(2):
- Short sequences of numbers, symbols or letters: single words, captions, alt text, UI labels.
- Source code, including SQL, infrastructure as code, YAML or JSON configuration, and comments that are part of the code.
- Machine-to-machine output that no person sees, such as agent-to-agent communication.
- Closed production workflows (for example in film or games), except for the final output.
The Code adds a concrete threshold for text: watermarking is required for free-form text longer than 200 tokens; below that it isn't.
There is also a "B2B" exemption that many teams read more broadly than it is. Under para. 87 of the Guidelines it only applies if all three conditions hold at once:
- The output is strictly technical (engineering designs, technical instructions, internal process documentation...).
- Only a limited, predefined group of professionals inside the provider's and deployer's organisations sees it.
- It is not meant to leave the company, with safeguards to prevent that (isolation, role-based access control).
Public- and consumer-facing systems are explicitly excluded. A SaaS that generates text your customer then sends to their own customers doesn't fit.
4. How to mark, by content type
The Code generally asks for at least two layers of machine-readable marking (for example, signed metadata plus an imperceptible watermark), because no single technique currently meets all four requirements of effectiveness, interoperability, robustness and reliability. There are two exceptions where one layer is enough, and one of them is exactly free-form text, which can't carry metadata.
4.1 Text: the mark lives in sampling
A text watermark doesn't add hidden characters. It statistically nudges how the model chooses between candidate tokens, following a secret key, and a detector with the same key looks for that pattern later. The direct engineering consequence: only whoever controls generation can apply it. If you use a model through an API, it's up to the provider; if you self-host, it's up to you.
If you use third-party APIs, the current picture is uneven and worth checking model by model:
- OpenAI announced its text watermark (textGrain) on October 5. In the API it is off by default: you have to enable it in organisation settings (Data controls > Text provenance) or per project, and select the models. If you haven't touched anything, your OpenAI API output is probably unmarked.
- Anthropic applies the mark at model level, across all its surfaces and regions, for supported models, and is adding it to models released before August 2. Check their table to see whether the exact model you use is covered, including the channel (direct API or cloud).
- Google: on the official developer forum, Google confirmed that Gemini API text carries SynthID, after initially saying the opposite. Until it's in the documentation, we would treat it as something to confirm in writing with the provider.
If you self-host open models, Hugging Face Transformers ships a SynthID Text implementation that you enable at generation time:
from transformers import AutoModelForCausalLM, AutoTokenizer, SynthIDTextWatermarkingConfig
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, padding_side="left")
model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
# The keys are a secret: load them from a secrets manager, never from the repo.
watermarking_config = SynthIDTextWatermarkingConfig(
keys=load_watermark_keys(), # list of ints, one per depth
ngram_len=5,
)
inputs = tokenizer([prompt], return_tensors="pt", padding=True)
out = model.generate(
**inputs,
watermarking_config=watermarking_config,
do_sample=True, # the watermark acts on sampling
max_new_tokens=512,
)Watermark keys become one more production secret: whoever holds them can detect your mark and potentially forge it. Treat them like your gateway API keys.
What to know about the limits, because you'll have to explain them to the business. OpenAI published figures for its own system that illustrate the problem well:
- At a target false-positive rate of 1%, it detected the mark in about 80% of 200-token passages and about 95% of 400-token ones, on content like psychology; much less on maths.
- Replacing 10% of the words in a 400-token passage with synonyms dropped detection from around 92% to 66%; replacing 25%, to 17%.
- In its test across the 24 official EU languages, Spanish had the best detection rate (69%) before the watermark strength was tuned.
In other words: a text watermark is a signal, not proof. Its presence doesn't prove authorship and its absence doesn't prove a human wrote it.
4.2 The trap is in your pipeline, not the model
This is what worries us most as a team that takes these systems to production. Many products don't return model output as is. It goes through intermediate steps that destroy the mark without anyone noticing:
- A second model that "rewrites" or "polishes" the answer. If that model doesn't mark (a small self-hosted model to cut costs, say), the final output is unmarked even if the first model marked it.
- Machine translation afterwards with another system.
- Templates that chop and reassemble generated text into short fragments.
- Image optimisers and CDNs that resize, convert to WebP or AVIF and strip metadata by default.
If a pipeline step substantially transforms the output with a model, that step is also generation and must mark. And if a step isn't a model but touches the content (a CDN, a converter), check that it preserves the marks.
4.3 Images, audio and video: signed metadata plus a watermark
For media, the pattern the Code asks for, and that the big providers already use, is two layers:
- Signed, timestamped metadata, secure and tamper-evident. The de facto standard is C2PA (Content Credentials).
- An imperceptible watermark in the content itself, which survives when metadata is lost (screenshots, conversions). C2PA lets you bind the two, so the watermark helps recover the credentials if they're stripped.
If you generate images with the OpenAI API or Claude, they already carry C2PA (and, for OpenAI, SynthID too). What you have to guarantee is that your pipeline doesn't remove them and, if you generate or edit media yourselves, that you add them. With the official c2pa-python library, marking an image as created by a generative model looks like this:
from c2pa import Builder, C2paBuilderIntent, C2paDigitalSourceType
# The signer uses your signing certificate, ideally kept in a KMS/HSM.
with Builder({}) as builder:
builder.set_intent(
C2paBuilderIntent.CREATE,
C2paDigitalSourceType.TRAINED_ALGORITHMIC_MEDIA, # "AI-generated"
)
with open("generated.jpg", "rb") as source, open("signed.jpg", "wb") as dest:
builder.sign(signer, "image/jpeg", source, dest)And a cheap CI test that catches the most common mistake, served images that no longer carry credentials:
#!/usr/bin/env sh
# check-c2pa-survives.sh: generate a test image, run it through the same
# pipeline as production (resize, conversion, CDN) and check the C2PA
# manifest is still there. Adapt the parsing to your c2patool version.
set -eu
./scripts/generate-test-image.sh > /tmp/in.jpg
./scripts/run-image-pipeline.sh /tmp/in.jpg /tmp/out.webp
if ! c2patool /tmp/out.webp > /tmp/manifest.json 2>/dev/null; then
echo "FAIL: processed image no longer has a C2PA manifest" >&2
exit 1
fi
grep -q "trainedAlgorithmicMedia" /tmp/manifest.json \
|| { echo "FAIL: manifest does not declare AI-generated content" >&2; exit 1; }5. Detectable is not the same as marked
Article 50(2) requires content to be detectable, not just marked. The Guidelines translate that into detection means being available to the people exposed to the content, with human-readable results. The Code goes further:
- Providers must offer a detection solution, in principle free of charge, hosted in the EU or runnable locally, and GDPR-compliant.
- Providers with fewer than one million monthly users whose detection has significant operating costs may charge a reasonable fee when a single user exceeds a reasonable query volume. Authorities, media, fact-checkers and researchers always get free access.
- By February 2, 2027, watermark detection must be interoperable across providers (for example via a standard API, a readable "signpost" pointing to the right detector, or a shared detector).
There is a real gap here worth knowing about: today, the big providers' text detectors have restricted access. OpenAI limits its text detector to approved research organisations, and Anthropic's detection API is in private preview, though it also opens it to enterprises that must verify the mark for their own compliance. For images and audio, OpenAI does offer a public verification API. If your system relies on a provider's mark, document how whoever needs detection will get it, and request the access that applies to you.
6. The provenance layer: how we'd build it
What works best for us is treating marking as an explicit layer in the output pipeline, with a decision per generated item and a record of why. Something like:
from dataclasses import dataclass
from enum import Enum
class Modality(Enum):
TEXT = "text"
IMAGE = "image"
AUDIO = "audio"
VIDEO = "video"
CODE = "code"
@dataclass(frozen=True)
class GeneratedOutput:
modality: Modality
token_count: int | None
audience: str # "public", "customer", "internal_restricted", "machine"
produced_by: str # exact model and version
upstream_marks: set[str] # e.g. {"provider_text_watermark", "c2pa"}
def marking_plan(out: GeneratedOutput) -> dict:
"""Decide which marks policy requires and record the reason."""
if out.modality is Modality.CODE:
return {"required": [], "reason": "source code: outside Art. 50(2)"}
if out.audience == "machine":
return {"required": [], "reason": "machine-to-machine, no human exposure"}
if out.audience == "internal_restricted":
# The B2B exemption needs all three conditions of para. 87.
# Code doesn't decide it: legal validates it and it's configured per system.
return {"required": [], "reason": "validated B2B exemption (ref. ADR-xxx)"}
if out.modality is Modality.TEXT:
if (out.token_count or 0) <= 200:
return {"required": [], "reason": "short text (≤200 tokens), no watermark required"}
return {"required": ["text_watermark"], "reason": "free-form text >200 tokens"}
# Image, audio and video: two layers.
return {"required": ["c2pa_signed", "invisible_watermark"], "reason": "synthetic media"}
def enforce(out: GeneratedOutput) -> None:
plan = marking_plan(out)
missing = set(plan["required"]) - normalize(out.upstream_marks)
audit_log(output=out, plan=plan, missing=missing)
if missing:
apply_or_block(out, missing) # mark here or don't publishWhat matters isn't the code itself but the decisions it forces:
- An inventory per model and per channel.
produced_byandupstream_markscome from a hand-maintained, verified table: which models mark, since when, with which technique, and on which channel (direct API, Bedrock, Vertex, Azure). That table is your evidence, and it looks a lot like the inventory (AIBOM) we covered in the previous post in this series, on LLM gateways. - Exemptions are configured, not inferred. Code shouldn't decide something is "B2B": that classification is validated once, documented and applied per system.
- The gateway is a good place for this. If you already route model calls through a gateway, it's the natural point to pin which models may serve public-facing content and check they have marking enabled.
7. Don't forget the 50(1) notice
The AI-interaction notice is the simplest thing to implement and the easiest to leave half done. The Guidelines ask for it at the latest at the first interaction, in a clear, distinguishable and accessible way, and warn that the "it's obvious" exception should be read narrowly. In practice:
- Show it on the first chat screen, not in the terms of use.
- Make channels without a visual interface announce it too: voice, WhatsApp, email.
- Review avatars and agents with a human name and tone. Those are exactly the cases where "obvious" stops being obvious.
8. Five mistakes we see coming
- Assuming the provider marks. At OpenAI, for example, it's off by default in the API.
- Checking in development, not production. The model, region or cloud channel change, and so does marking coverage.
- Breaking the mark in an intermediate step: rewriting with another model, translation, image optimisation.
- Defaulting to the B2B exemption for a product that ends up sending content to third parties.
- Leaving no trail. If a request comes in, the question will be which technique you use, why and how you checked it. Without a record, that answer doesn't exist.
Checklist: Article 50 before December 2
Scope
- [ ] We have a list of systems that generate text, image, audio or video for people in the EU, with their market launch date (before or after August 2, 2026).
- [ ] For each one we know whether we're provider, deployer or both, validated with legal.
- [ ] Exemptions (code, machine-to-machine, para. 87 B2B) are documented per system, with all three conditions when B2B applies.
Marking
- [ ] There's a verified table of which models and channels mark text and how; at OpenAI, text watermarking is enabled at org or project level for the models we use.
- [ ] Free-form text over 200 tokens that reaches users is marked, including text that passes through rewriting or translation steps.
- [ ] Images, audio and video carry two layers: signed C2PA metadata and an imperceptible watermark.
- [ ] A CI test checks that marks survive the real pipeline (resize, conversion, CDN).
- [ ] Watermark keys and C2PA signing certificates live in a secrets manager, with rotation and least-privilege access.
- [ ] Terms of use prohibit removing the marks.
Detection
- [ ] We know how content from each system is detected and who can access the detector; we've requested access where we rely on a provider's.
- [ ] We have a plan for detection interoperability before February 2, 2027.
Interface and deployment
- [ ] Chatbots, agents and avatars disclose they're AI at the start of the first interaction, on every channel.
- [ ] If we publish deepfakes or public-interest text without editorial review, they carry a visible or audible label.
Evidence
- [ ] Every marking decision is logged (system, model, technique, reason), and a document explains why we chose those techniques.
Conclusion
Article 50 doesn't ban anything: it asks for transparency. But in a real product, transparency is an engineering problem. "The AI" doesn't apply the mark: a specific step in a specific pipeline does, and another step can remove it. That's why it isn't solved with a line in the terms of use, but with inventory, tests and logging, like any other non-functional requirement that matters.
There's a month left until December 2. That's plenty of time to take inventory, turn on what your providers already offer, add a CI test and document your decisions. It isn't if you start in the last week.
If you'd like to review how your product fits Article 50 from the technical side (what gets marked, where it gets lost and what evidence you have), we'd be happy to have that conversation. No pitch: a 30-minute call with one of our engineers.