What you are actually being asked to build
The requirement sounds simple. If your system generates content that will be published, that content should carry a marker saying it was machine-generated, in a form a machine can read. Two lines in a regulation; a surprising amount of engineering underneath.
The subtlety is that content moves. An image generated by your service gets downloaded, re-encoded by a messaging app, cropped, screenshotted, pasted into a document, exported to PDF and re-uploaded somewhere else. At each hop, something might discard whatever you attached. A marking scheme that only works while the file is untouched is a compliance artefact rather than a functioning system, and the difference matters if anyone ever asks you to prove where a particular asset came from.
So the design question is not "which field do I set". It is: what claim am I making, who can verify it, what survives which transformations, and what do I do when nothing survives at all. This guide works through each of those in the order you will hit them.
Dates in this area move. As of August 2026, the EU AI Act's Article 50 transparency duties apply, with a limited later date for the watermarking element under Article 50(2) applying to systems already on the market. Other jurisdictions have their own timetables. Treat any specific date in this guide as a pointer to check the current position with counsel rather than as advice — the engineering patterns below outlast the deadlines.
The four obligations, and which one is technical
Transparency requirements in this space usually decompose into four distinct duties, and teams tend to conflate them. Separating them tells you what to build.
| Duty | Applies to | Where it is satisfied | Engineering effort |
|---|---|---|---|
| Tell users they are talking to an AI | Conversational systems | Interface copy, first-turn disclosure | Low — design and copy |
| Mark generated output machine-readably | Content intended for dissemination | Manifest, watermark, or both | High — the subject of this guide |
| Disclose deepfakes of real people | Realistic depictions of identifiable persons | Visible label plus machine-readable mark | Medium — needs a detection or classification step |
| Keep records of what you generated | Operational and evidentiary need | Server-side log | Low — but easy to under-scope on retention |
The first duty is a design task. The third needs a classifier or a product rule about what your system will produce. The fourth is ordinary logging, done with a little care about what you store and for how long. The second is where the interesting engineering lives, and it is what the rest of this guide covers.
What a C2PA manifest actually is
Content Credentials, the user-facing name for the C2PA standard, is a way of attaching a signed, tamper-evident record of an asset's history to the asset itself. Strip away the branding and it is four concepts.
Assertions
An assertion is a single statement about the asset: that it was created with a particular tool, that a specific action such as a crop or a colour adjustment was applied, that it contains AI-generated content, who the creator was. Assertions are structured data, and the standard defines common ones so that different tools mean the same thing by them.
The claim
A claim gathers a set of assertions together with cryptographic hashes of the asset's content, so that any subsequent modification to the bytes invalidates the claim. This is what makes the record tamper-evident rather than merely descriptive: you cannot change the pixels and keep a valid claim about them.
The signature
The claim is signed with a certificate belonging to whoever is asserting it. Verification checks the signature, checks the hashes against the current bytes, and reports whether the record is intact and who stands behind it.
The manifest and the chain
The manifest wraps the claim and its signature and is embedded in the asset's container. When an asset is edited by another tool that understands the standard, a new manifest is added referencing the previous one, producing a chain that shows the sequence of operations rather than only the final state.
The practical shape of a generation-time manifest is small. What follows is illustrative rather than a literal serialisation — read it as the shape of what you are asserting.
{
"claim_generator": "yourproduct/2.4.0 c2pa-rs/0.4x",
"format": "image/jpeg",
"assertions": [
{
"label": "c2pa.actions",
"data": {
"actions": [
{ "action": "c2pa.created",
"digitalSourceType":
"http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia" }
]
}
},
{
"label": "stds.schema-org.CreativeWork",
"data": {
"@context": "https://schema.org",
"@type": "CreativeWork",
"author": [ { "@type": "Organization", "name": "Your Company Ltd" } ]
}
}
]
}
The load-bearing part is the digitalSourceType value. The IPTC vocabulary distinguishes fully synthetic media from content that was captured and then algorithmically modified, and from composites of both. Choosing the wrong term is the most common substantive error in a first implementation, because it makes a claim about your pipeline that is not true.
Decide the source-type taxonomy for every generation path in your product before you write any signing code, and write it down. A text-to-image path, an inpainting path that modifies a user's photograph, and an upscaling path are three different claims. Teams that skip this step usually end up asserting "fully synthetic" everywhere, which is wrong for any pipeline that touches user-supplied media and is exactly the kind of inaccuracy an auditor notices.
The trust model, and precisely where it breaks
Provenance metadata answers one question well and another question not at all. It is worth being blunt about which is which, because a lot of public discussion muddles them.
What it establishes: that a particular party asserted a particular history for this exact byte sequence, and that neither the assertion nor the bytes have changed since. That is a real, cryptographically meaningful guarantee, and it is the basis for a verifier being able to say "this came from a signer you can identify".
What it does not establish: that content without a manifest is not AI-generated. The absence of a credential means nothing at all. This asymmetry is the single most important property of the whole system, and it has three consequences.
- Stripping is trivial and unattributable. Any re-encode discards the manifest. Screenshotting discards it. Many platforms strip metadata on upload as a privacy measure. None of this requires intent, so a missing manifest carries no signal about whether someone was hiding something.
- Verification depends on trusting the signer. A valid signature from a certificate you have no reason to trust tells you the file is unmodified since signing, not that its claims are true. The value of the system rests on a trust list, and on who is on it.
- It cannot detect anything. Provenance is a declaration made at creation time by a cooperating producer. It does nothing about a bad actor who never attaches a manifest in the first place. Anyone framing this as a solution to synthetic media is describing something the technology does not do.
Understanding this properly changes your design. If you build assuming the manifest is your only mechanism, your system fails silently and often. If you build assuming it is one signal among several, you get something that degrades gracefully.
Layer the mechanisms, because each one fails differently
The European Commission's draft Code of Practice on marking and labelling AI-generated content describes exactly this layered posture: metadata embedding, imperceptible watermarking, and logging. That is not regulatory box-ticking. It is a straightforward reading of the failure modes.
| Mechanism | Information capacity | Survives re-encode | Survives screenshot | Fails when |
|---|---|---|---|---|
| Signed manifest | High — full structured history | No | No | Any pipeline strips metadata |
| Imperceptible watermark | Low — a few bits to an identifier | Usually | Usually | Heavy crops, filters, adversarial removal |
| Visible label | Minimal | Yes | Yes | Cropped off; not machine-readable |
| Server-side generation log | Complete, but private | Not applicable | Not applicable | Requires a lookup and a matching hash |
Read down the "fails when" column and the case for all four is obvious. The manifest carries the detail. The watermark carries a durable minimum. The visible label serves the human. The log lets you answer a question weeks later about an asset that arrived stripped of everything else.
Log the perceptual hash and the manifest identifier of every asset you generate, with a retention period you have consciously chosen. When someone sends you a stripped file and asks whether your system produced it, that log is the only thing that can answer. Choose the retention period deliberately — this is generation metadata, and if the assets are user content, your data protection position under the DPDP Act or the UK GDPR needs to accommodate it. The redaction patterns in our guide to PII redaction in pipelines apply here too.
Every article here is written by a Verified Builder. Want your name on the next one?
AI Tech Connect lists AI engineers, founders and researchers across India and the UK — and the people hiring browse it to find them. Adding your profile is free.
Become a Verified Builder →Implementing it: the parts that actually take time
Signing is the easy bit
Attaching a manifest is a small amount of code. Open-source implementations exist for the common languages, and the operation is a hash plus a signature over a structure you assemble. In a generation service, it slots in immediately before you return or store the asset.
# Conceptual shape of a signing step in a generation service.
# Library APIs differ; the sequence does not.
def sign_generated_asset(asset_bytes, mime_type, pipeline):
manifest = build_manifest(
claim_generator=f"{PRODUCT}/{VERSION}",
format=mime_type,
source_type=pipeline.digital_source_type, # decided per pipeline
actions=pipeline.actions, # created / edited / composited
)
signed = c2pa.sign(
asset=asset_bytes,
manifest=manifest,
signer=SIGNER, # certificate + key, from the KMS/HSM
)
log_generation(
manifest_id=signed.manifest_id,
content_hash=sha256(asset_bytes),
perceptual_hash=phash(asset_bytes),
pipeline=pipeline.name,
)
return signed.asset_bytes
Key management is where the real decisions are
The signing key is the trust anchor for every claim you make. Compromise it and someone can produce assets that verify as yours. This is a hardware security module or a managed key service, not a file on a container image, and the certificate needs a rotation plan that does not invalidate historical assets — which means keeping the ability to verify against retired certificates.
Certificate provenance also matters for whether anyone believes you. A self-signed certificate produces a manifest that verifies cryptographically but resolves to a signer that consumer tooling has no reason to trust. If your assets are meant to be verifiable by third parties rather than only by your own product, the certificate needs to chain to something recognised, and that is a procurement task with a lead time. Start it early.
Your own pipeline is the most likely place manifests die
This is the failure I would bet on in any first implementation. You sign at generation, and then your own storage layer generates thumbnails, your CDN re-encodes to a modern format, your image proxy resizes on the fly, and every one of those steps quietly drops the manifest. The asset reaching the user carries nothing.
The audit is mechanical and worth doing before you write any signing code: list every process that touches the bytes between generation and delivery, and test each one for whether metadata survives. You will find at least one that does not.
Format conversion is the usual culprit and the easiest to miss, because it often happens in a managed service you did not write. If your CDN serves modern image formats automatically, verify that the transcoded output retains the manifest. If it does not, you need either to disable that optimisation for signed assets, re-sign after transcoding, or accept that the manifest only exists on the original and lean harder on the watermark and log layers.
Text: the case with no good answer
Images, audio and video have containers with somewhere to put metadata. Text usually does not. A paragraph copied into an email is a sequence of characters with nowhere to hide a signature.
The standard has moved in this direction — C2PA specification 2.3 extended manifests to unstructured text, alongside support for live video streaming — and that genuinely helps for text that travels as a file, or through a system that preserves a sidecar. It does nothing for text that a user selects, copies and pastes, which is most text.
Statistical watermarking of generated text exists as a research direction, embedding a detectable bias in token selection. It is real work, but it degrades under paraphrase, is weakened by short outputs, and generally requires the detector to hold a secret shared with the generator. Do not plan a product around it.
What actually works is narrower and more honest, and it is three things:
- Mark the container when there is one. If your product emits documents, reports or files, attach a manifest. That covers more output than teams expect once they look.
- Disclose at the surface you control. A visible, persistent indication in your interface that content was machine-generated, delivered at the point the user sees it rather than in a settings page. This is the duty most likely to be assessed on whether an ordinary user would actually notice.
- Offer a verification path. An endpoint that takes a string and reports whether your system generated it, backed by your generation log. This is the only mechanism that survives copy-and-paste, and it is entirely within your control to build.
Build or buy
For a team in Bengaluru or Bristol with an ordinary engineering budget, the split is fairly clear.
| Component | Recommendation | Reasoning |
|---|---|---|
| Manifest creation and signing | Build on an open-source library | Well-specified, stable, low ongoing cost |
| Key custody | Buy — managed KMS or HSM | Never a good place to be original |
| Certificate chaining to a trusted root | Buy | Not something you can self-provision credibly |
| Imperceptible watermarking | Buy, or use your model provider's | Robustness research is a specialist discipline |
| Generation log and verification endpoint | Build | Trivial, and only you have the data |
| Deepfake classification for the disclosure duty | Depends | Often a product rule beats a classifier |
That last row deserves a note. If the duty is to disclose realistic depictions of identifiable real people, one option is a classifier that decides whether a given output qualifies. Another is a product rule — for example, always labelling any output from a photorealistic human-image pipeline — which is less precise but has no false negatives and no model to maintain. For most teams the product rule is the better engineering decision, and it is much easier to explain to a regulator.
A shipping checklist
Run these in order. Each one is a place teams get stuck.
- Enumerate every generation path in your product and assign each one a digital source type. Write it down and have someone who understands the pipelines check it.
- Decide which paths produce content "intended for dissemination", since that phrase is doing significant work in the obligation and internal-only output may be out of scope.
- Provision signing keys in a managed service. Decide your rotation policy and confirm you can still verify assets signed with a retired certificate.
- Start the certificate procurement conversation now if third-party verifiability matters. It has a lead time.
- Audit every processing step between generation and delivery for metadata survival. Fix or document each failure.
- Add generation logging with content and perceptual hashes, with a retention period you have deliberately chosen and can justify.
- Add the visible disclosure at the surface, not buried in settings.
- Add a verification endpoint for stripped assets.
- Write the internal note explaining what your marking does and does not prove, so that whoever answers the first customer question gets it right.
None of this is intellectually difficult. It is a sequence of small, unglamorous decisions that compound into a system which either tells the truth about your output or does not. Teams that treat it as a compliance checkbox ship the signing step and nothing else, then discover eighteen months later that their CDN has been stripping manifests since launch. Teams that treat it as an engineering problem end up with something genuinely useful: the ability to answer, quickly and credibly, where a piece of content came from. More deployment guides are collected in our tips section.