Open source · EU AI Act Article 50

Make your AI app transparent in an afternoon

Mark AI-generated images with two invisible layers, tell users they are talking to an AI in 24 languages, and verify any file — with one TypeScript toolkit that runs everywhere.

npm install @filigranejs/core @filigranejs/ui

Three obligations, one toolkit

Article 50 of the AI Act applies since 2 August 2026, with fines up to €15 million or 3 % of worldwide turnover.

Art. 50(1)

Disclose chatbots

People must know they are interacting with an AI system, at the latest at the first interaction.

<ai-disclosure>

Art. 50(2)

Mark generated content

Outputs must be machine-readable and detectable as AI-generated. The Code of Practice expects at least two marking layers.

markImage() · markText()

Art. 50(4)

Label deepfakes and AI text

Deployers must visibly label deepfakes and AI text published on matters of public interest.

<ai-label>

Three layers that back each other up

Metadata can be stripped by a social network. Pixels can be edited. Together, the layers keep the signal alive.

1

Signed C2PA manifest (Content Credentials)

A cryptographically signed record of how the image was made. Any edit to the file breaks the signature, so tampering is evident.

Tamper-evidentIndustry standardLost if metadata is stripped
2

IPTC “Digital Source Type” metadata

The flag search engines, social networks and photo tools already read to show “AI-generated”.

Widely supportedLost if metadata is stripped
3

Invisible watermark in the pixels

A 64-bit code spread over thousands of frequency coefficients, invisible to the eye (≈ 43 dB PSNR), linked to the manifest.

Survives JPEG recompressionSurvives resizingSurvives metadata strippingNot yet: cropping

A few lines in the stack you already use

Pure TypeScript, zero native dependencies: Node.js, browsers, Deno, Bun and edge runtimes.

import { createLocalSigner, markImage } from '@filigranejs/core';

const signer = await createLocalSigner({ certificate, privateKey });

// After your model returns an image:
const { bytes, layers } = await markImage(png, {
  signer,
  model: { name: 'gpt-image-1' },
});
// layers → ['watermark', 'metadata', 'c2pa']

Live components, every EU language

Accessible, themable with CSS variables, and they keep a visible “AI” chip after the banner is dismissed.

Labels use the official EU icons (free to use).
3marking layers
24EU languages
0native dependencies
MITfree licence

Questions

Does Filigrane make me compliant?

It implements the technical measures described in the Commission’s Code of Practice: multi-layer marking, detection and visible disclosure. Compliance also depends on your role, your product and how you publish content — this is not legal advice.

Which certificate do I sign with?

For production, use a certificate from a certification authority on the C2PA trust list. For tests, `filigrane keygen` creates a development certificate: manifests are valid but shown as “untrusted”.

Does the verifier upload my files?

No. Everything runs in your browser; the file never leaves your device.

How robust is the watermark?

It survives JPEG recompression down to quality 50, resizing, brightness changes and metadata stripping. Cropping and rotation are not supported yet. Every release is tested automatically.

Is it compatible with other C2PA tools?

Yes. Every commit is checked against the C2PA reference implementation (c2pa-rs), and Filigrane reads manifests produced by other tools.