TheAlgoBrief

How to Add C2PA Metadata to AI Ad Creatives (Step-by-Step)

7 min readTheAlgoBrief Team
C2PAIABAI disclosuread techmetadatacompliancec2pa-nodecontent credentials
The Short Answer

C2PA metadata is a cryptographically signed provenance framework used to embed verifiable history directly into digital assets. Under the IAB AI Transparency and Disclosure Framework, advertisers must embed a C2PA manifest containing two specific custom assertions—com.iab.threshold and com.iab.disclosure—into every AI-involved ad creative prior to distribution. For tools that do not automatically add manifests (e.g., Midjourney, Runway), engineers must use SDKs like c2pa-node to create and sign the manifest from scratch. For tools that do (e.g., Adobe Firefly), the manifest must be updated to append the IAB assertions while preserving the parent ingredient chain.

The IAB AI Transparency and Disclosure Framework requires that every AI-involved ad asset carry machine-readable provenance metadata before it goes into distribution. That metadata lives in a C2PA manifest — a cryptographically signed record embedded directly in the file.

This guide is for engineers and technical creative teams who need to implement that requirement. It covers the two scenarios that actually exist in production pipelines: creatives from tools that already write C2PA (like Adobe Firefly or Photoshop), and creatives from tools that do not (Midjourney, Runway, Stable Diffusion, ElevenLabs). Both paths converge on the exact same mandatory IAB custom assertions.

If you are still deciding whether a creative needs disclosure at all, utilize the IAB AI Materiality Checker process first, then come back here to implement.

What the IAB Framework Actually Requires in Metadata

Before touching any code, it is critical to understand what the framework demands. The IAB AI Transparency and Disclosure Framework specifies two IAB custom C2PA assertions that must be embedded in every AI-involved creative before distribution:

AssertionKeyAllowed ValuesWho Determines It
Disclosure thresholdcom.iab.threshold"met" or "not met"Human (compliance lead or materiality checker)
Consumer disclosure appliedcom.iab.disclosure"yes" or "no"Human (creative/ops team)

Both of these assertions are mandatory regardless of whether a visible consumer-facing label appears on the ad. The metadata acts as the B2B audit layer — traveling with the asset to agencies, publishers, platforms, and regulators. If the asset has no manifest, or the manifest is missing these specific assertions, the creative is fundamentally non-compliant under the IAB framework.

Beyond the IAB assertions, your manifest should also definitively include:

TL;DR — Key Takeaways
  • Mandatory Assertions: Every AI-involved creative must include com.iab.threshold and com.iab.disclosure C2PA assertions.
  • No Manifest Default: Tools like Midjourney and Runway do not generate C2PA metadata; you must build and sign manifests from scratch.
  • Existing Manifest Updates: Tools like Adobe Firefly generate a base C2PA manifest, but you must append the IAB assertions programmatically while preserving the ingredient chain.
  • Verification is Critical: Always verify the signed manifest before distribution; image optimization steps often strip XMP metadata unintentionally.

Step 0: Determine Your IPTC digitalSourceType Value

The IPTC (International Press Telecommunications Council) digitalSourceType vocabulary is the standard C2PA uses to classify how content was created. You need to identify the correct value before writing any code.

The most commonly applicable values for advertising creatives include:

digitalSourceType ValueWhen to Use It
trainedAlgorithmicMediaFully AI-generated image, video, or audio from a generative model (e.g., Midjourney, Runway Gen-3, Sora).
compositeWithTrainedAlgorithmicMediaHuman-originated base asset with AI-generated elements composited in (e.g., a real product photo with an AI-replaced background).
algorithmicMediaAI-processed but not generative — traditional ML processing, upscaling, noise reduction.
digitalCaptureReal photograph or live-action video with absolutely no AI generation involved.

For the vast majority of AI ad creatives, you will use trainedAlgorithmicMedia or compositeWithTrainedAlgorithmicMedia. For instance, if you composite a Midjourney-generated background behind a photographed product prominently, that requires compositeWithTrainedAlgorithmicMedia.

Step 1: Check Whether Your Creative Tool Already Wrote a Manifest

This determines your entire implementation workflow. Run a quick audit before writing scripts.

Tools that write C2PA manifests automatically

Adobe Firefly (in Photoshop, Illustrator, Express) and Adobe Stock AI-generated assets embed Content Credentials by default for any AI-generated or edited element. The manifest includes generation method, tool name, and timestamp. However, it does not include the IAB custom assertions (com.iab.threshold and com.iab.disclosure).

Tools that write no manifest at all

If your pipeline relies on these tools, you are starting from scratch and must create a full manifest.

How to Check Programmatically

You can easily inspect an asset using the c2pa-cli:

# Install the C2PA CLI tool
npm install -g c2pa-cli

# Inspect any asset
c2patool inspect ./your-creative.jpg --output json

If the output shows "manifests": {}, you are in the create-from-scratch path. If it returns a populated manifest object, you must update the existing manifest.

Step 2A: If No Manifest Exists — Create One from Scratch

First, install c2pa-node, the official Node.js binding for the C2PA Rust SDK.

npm install c2pa-node

c2pa-node requires a signing certificate. For development, you can generate a self-signed certificate. For production, you must use a certificate from your PKI or a trusted CA so the signer entity is legally identifiable.

# Generate a self-signed cert for development ONLY
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
  -days 365 -nodes -subj "/CN=YourAgencyName"

Full Manifest Creation Code Example

import { createC2pa, ManifestBuilder } from 'c2pa-node';
import { readFile, writeFile } from 'fs/promises';

const c2pa = await createC2pa({
  signer: {
    privateKey: await readFile('./key.pem'),
    certificate: await readFile('./cert.pem'),
    algorithm: 'ps256',
    tsaUrl: 'http://timestamp.digicert.com',
  },
});

const manifest = new ManifestBuilder({
  claim_generator: 'YourAgency/CompliancePipeline/1.0',
  format: 'image/jpeg',
  title: 'hero-banner-q2-campaign.jpg',

  assertions: [
    // IPTC source type
    {
      label: 'stds.iptc.photo-metadata',
      data: {
        'Iptc4xmpExt:DigitalSourceType': 'http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia',
      },
    },
    // AI involvement description
    {
      label: 'c2pa.ai_info',
      data: {
        description: 'Hero banner image fully generated by Midjourney v6.',
        aiTool: 'Midjourney v6',
        aiInvolvementType: 'text-to-image generation',
      },
    },
    // IAB custom assertions
    {
      label: 'com.iab.threshold',
      data: {
        value: 'met',
        rationale: 'Photorealistic AI-generated human in primary role',
        assessedBy: 'compliance-lead@youragency.com',
        assessedAt: new Date().toISOString(),
      },
    },
    {
      label: 'com.iab.disclosure',
      data: {
        value: 'yes',
        labelText: 'AI-generated image',
        labelPlacement: 'overlay-bottom-left',
        appliedAt: new Date().toISOString(),
      },
    },
  ],
});

const inputBuffer = await readFile('./hero-banner.jpg');

const { signedAsset } = await c2pa.sign({
  asset: { mimeType: 'image/jpeg', buffer: inputBuffer },
  manifest,
});

await writeFile('./hero-banner-c2pa.jpg', signedAsset.buffer);
console.log('C2PA manifest embedded successfully.');

The com.iab.threshold and com.iab.disclosure values are explicit editorial decisions made by a human. Extract them from your compliance workflow database before executing the script.

Step 2B: If a Manifest Already Exists — Update It

When dealing with Adobe Firefly assets, you cannot simply overwrite the manifest. Each update must be appended as a new ingredient that references the original, creating an auditable provenance chain.

import { createC2pa, ManifestBuilder } from 'c2pa-node';
import { readFile, writeFile } from 'fs/promises';

const c2pa = await createC2pa({ /* signer config */ });
const inputBuffer = await readFile('./firefly-export.jpg');

const updateManifest = new ManifestBuilder({
  claim_generator: 'YourAgency/CompliancePipeline/1.0',
  format: 'image/jpeg',
  title: 'firefly-hero-banner-iab-compliant.jpg',

  ingredients: [
    {
      title: 'firefly-export.jpg',
      relationship: 'parentOf',
      asset: { mimeType: 'image/jpeg', buffer: inputBuffer },
    },
  ],

  assertions: [
    {
      label: 'com.iab.threshold',
      data: {
        value: 'met',
        rationale: 'AI-generated photorealistic background scene',
        assessedBy: 'compliance-lead@youragency.com',
        assessedAt: new Date().toISOString(),
      },
    },
    {
      label: 'com.iab.disclosure',
      data: {
        value: 'yes',
        labelText: 'AI-generated image',
        labelPlacement: 'overlay-bottom-left',
        appliedAt: new Date().toISOString(),
      },
    },
  ],
});

const { signedAsset } = await c2pa.sign({
  asset: { mimeType: 'image/jpeg', buffer: inputBuffer },
  manifest: updateManifest,
});

await writeFile('./firefly-hero-banner-iab-compliant.jpg', signedAsset.buffer);
console.log('IAB assertions appended successfully.');

The ingredients array preserves the chain of custody. Verifiers and platforms can traverse the chain backwards to see the exact generative origins while simultaneously verifying your agency's compliance stamp.

Step 3: Handle Video and Audio Creatives

The exact same implementation pattern applies to video (MP4, WebM) and audio (MP3, WAV) assets. You must provide format-specific MIME types and tailor your AI descriptions accordingly.

Remember, for a generic synthetic voice that does not mimic a real person, your compliance check might determine com.iab.threshold is "not met". However, the assertion itself must still be fundamentally embedded into the file.

Step 4: Verify the Manifest Before Distribution

Never ship an asset from your signing pipeline directly to trafficking without verification. Image optimization workflows frequently strip XMP metadata accidentally, destroying the carefully constructed manifest.

c2patool inspect ./hero-banner-c2pa.jpg --output json | jq '.manifests | .[] | .assertions | .[] | select(.label | startswith("com.iab"))'

If either the threshold or disclosure assertion is missing from the output, the asset is strictly non-compliant and must be rejected before trafficking. Integrating automated verification steps into your CI/CD pipeline guarantees flawless compliance continuously.


Frequently Asked Questions

Not automatically. JPEG to WebP conversion, for example, will typically strip XMP-embedded manifests unless your conversion tool explicitly preserves them. Always re-verify after conversion. The safest approach is to sign after all format optimization is complete.
Yes. You can sign a retroactive manifest. You cannot backdate the timestamp — any trustworthy signing uses a timestamp authority (TSA) that records the actual signing time. But you can sign existing assets and document the original creation date in the manifest's AI info assertion.
The IAB framework places accountability on the advertiser (brand and/or agency). In practice, whoever controls the creative asset at the point closest to trafficking should do the final signing. In a multi-agency workflow, establish this in your contracts and SLAs explicitly.
No. The IAB framework requires C2PA metadata for all AI-involved assets, whether or not consumer disclosure is required. The manifest proves you made the assessment. An asset with no manifest is indistinguishable from one where no assessment was made.
Revoked certificates invalidate the signature verification, but your TSA-anchored timestamp still proves when the signing occurred. For operational continuity, set up certificate renewal alerts and rotate signing certificates before expiry.
No. As of early 2026, tools like Midjourney, Runway (Gen-2/Gen-3), and Stable Diffusion do not automatically generate or embed C2PA manifests. You must create and embed the manifest from scratch using libraries like c2pa-node.
No. While Adobe Firefly automatically embeds a base C2PA manifest with Content Credentials, it does not include the com.iab.threshold or com.iab.disclosure custom assertions. You must append these manually using a compliant SDK.
For a fully AI-generated image directly exported from a generative model (e.g., Midjourney or DALL-E), you should use the IPTC digitalSourceType value 'trainedAlgorithmicMedia'.