Article 50 of the EU AI Act became applicable on 2 August 2026. It is one of the few provisions in the regulation that turns into an engineering ticket rather than a policy document: a system that generates images, audio or video must produce outputs that an automated tool can detect as artificially generated.
We build CasaNova Labs, an AI studio for real estate photo and video editing, and we shipped this ahead of the date across every image and every video the product outputs. What follows isn't a legal explainer — it's what the requirement means at the file level, and the three traps that will make a pipeline ship unmarked files while every test stays green.
Two obligations, two different actors
The single most useful thing to get right before writing any code: Article 50 bundles requirements that fall on different parties, and they are satisfied by different mechanisms.
- §2 binds the provider of the generative system. Every synthetic output must carry marking in a machine-readable format. Nothing in it is about human visibility.
- §4 binds the deployer — whoever publishes the content. Where the content qualifies as a deepfake under Art. 3(60), manipulated content resembling existing people, objects or places in a way that could pass as authentic, it must be disclosed "in a clear and recognisable manner."
That distinction has a direct architectural consequence: §2 is metadata a detector parses, §4 is a label a human reads. They are two separate pipelines with two separate failure modes, and conflating them is the most common design mistake we've seen discussed.
For our part, the claim we make and the only one: our outputs carry machine-readable marking within the meaning of Article 50(2).
What "machine-readable" resolves to
There is no bespoke format to invent. Detectors converge on the IPTC DigitalSourceType property, and the controlled-vocabulary value that matters for generated content is trainedAlgorithmicMedia. Written into an XMP packet, it is what an automated checker actually looks for — a string a parser can match, rather than a free-text note in a description field that no tool will ever read.
For still images that packet sits alongside standard EXIF fields. For MP4, it goes into a top-level uuid box carrying the UUID reserved for XMP by the XMP specification (Part 3, Storage in Files) — no re-encode required, since an MP4 is a flat sequence of [size][type][payload] boxes.
So far, so mechanical. The interesting part is everything that quietly removes it again.
Trap 1 — your own resize eats the metadata
Most image processing libraries drop metadata on transform by default; it's the safe behaviour for them and the wrong one for you. A thumbnail route that resizes on the fly will serve a file with no marking whatsoever, no matter what the stored original carries.
// strips EXIF/XMP — the thumbnail ships unmarked
await sharp(input).resize({ width: 320 }).webp().toBuffer();
// preserves it
await sharp(input).resize({ width: 320 }).withMetadata().webp().toBuffer();
Nothing throws. The image looks perfect. Audit every path that re-encodes an image between storage and the client, not just the one that writes it — delivery-time transforms are where this hides.
Trap 2 — in MP4, where you write it decides whether the file still plays
Appending a box to an MP4 is only safe at the end. The moov atom's stco table holds absolute byte offsets into mdat: insert anything before mdat and every one of those offsets is now wrong. This is not theoretical — a box inserted right after ftyp gives a file that decodes zero frames with Invalid NAL unit size. Appended after the last box, nothing shifts and playback is untouched.
If you take one thing from this article: append, never insert.
Trap 3 — the visible label destroys the machine marking
This one only appears once both obligations are implemented, which is why it tends to be found late.
A §4 visible label on video means overlaying a rendered label on every frame, which means a full re-encode. And a re-encode rebuilds the container from scratch — wiping out any uuid box you appended beforehand. Run the two steps in the intuitive order (machine marking first, since it's the cheap one) and the §2 marking silently disappears from every single video you ship.
The correct order is the counter-intuitive one: visible mark first, machine marking last. Whatever writes to the container has to be the final operation in the chain.
There's a broader version of this rule worth internalising: the marking step belongs at the single choke point every output passes through on its way to storage, and it belongs after every transform. Anything that runs later gets to undo it.
Closing
Article 50(2) is a small, mechanical requirement once you separate it cleanly from §4: write a controlled-vocabulary metadata field, in a format that survives your own transforms, at the one point every output funnels through. The whole difficulty is in ordering — and none of the three traps above produce an error, a log line or a failing test. They produce a file that looks correct and isn't marked.
We shipped this across every image and video CasaNova Labs produces, ahead of the 2 August 2026 date. If you're building on the generation side, the three ordering rules above are what the requirement actually costs you: an afternoon, and knowing where to look.
Top comments (0)