Skip to main content

Assertions

An assertion is a { label, data } object in the manifest's assertions array. Use it to attach your own metadata to the manifest. You can write one by hand, or use the typed CAWG helpers from the @limboai/verifox-sdk-issuer/assertions subpath. The helpers build the data payload and type it against @contentauth/c2pa-types. They are runtime-agnostic, so they work in both the Node and browser builds.

Assertions are for your namespace only

The assertions array carries client-namespaced metadata. The c2pa.* and cawg.identity namespaces belong to the signer: it derives those assertions from the typed request fields and rejects them if you submit them here.

That means C2PA actions are not assertions. You do not hand-write a c2pa.actions assertion — you describe provenance as facts through the manifest's origin, components, and actions fields, and the signer authors the structural C2PA assertions for you:

  • origin{ sourceType } for an original (c2pa.created) or { parent } for a derivative (c2pa.opened). See Ingredients.
  • components — assets composited in or fed to a process; the signer derives c2pa.placed / c2pa.removed and the ingredient relationships.
  • actions — workflow actions applied to the asset, e.g. { kind: "edited" }, { kind: "published" }.

Verified identity likewise goes through the identity field, not an assertion. See Identity.

Which labels are accepted

Two things constrain the label you can attach:

  • Reserved namespaces. c2pa.* and cawg.identity belong to the signer — it authors those from the typed fields and rejects them if you submit them here. This is part of the SDK's request schema, so the SDK catches it locally, before the request is sent.
  • A deployment allowlist. Beyond the reserved namespaces, which labels are accepted is deployment policy, enforced by the signing service. The service in front of the signer can narrow the set per integration, so the effective allowlist isn't something the client can pre-check — a disallowed label is rejected server-side with an invalid error.

So a raw label like org.example.custom works only if your deployment allows it. If you're unsure which labels are enabled for your integration, ask whoever operates your signing service.

Raw assertions vs typed helpers

The assertions field is optional and takes an array of Assertion objects (omit it, or pass [], when you have none):

type Assertion = { label: string; data: any };

Pass a raw object directly for any allowlisted label:

// works when the deployment allowlists "stds.schema-org.CreativeWork"
const assertions = [
{ label: "stds.schema-org.CreativeWork", data: { "@type": "ImageObject" } },
];

Or use a typed CAWG helper, which returns the same { label, data } shape with the payload built and validated:

HelperAssertion labelCovers
cawgMetadataAssertioncawg.metadataCAWG Dublin Core title and description
cawgTrainingMiningAssertioncawg.training-miningCAWG AI training and data-mining permissions

cawgMetadataAssertion

cawgMetadataAssertion({ title?, description? }) builds a cawg.metadata assertion carrying Dublin Core fields: a human-readable title and description that inspectors render alongside the asset.

import { cawgMetadataAssertion } from "@limboai/verifox-sdk-issuer/assertions";

const meta = cawgMetadataAssertion({
title: "Sunset over the bay",
description: "Long exposure shot from the north pier, October 2026.",
});

cawgTrainingMiningAssertion

cawgTrainingMiningAssertion({ aiInference?, aiGenerativeTraining? }) builds a cawg.training-mining assertion. It records, on the asset itself, whether the creator permits the content to be used for AI inference and for generative-AI training or data mining. A crawler or dataset builder that honours C2PA can read this assertion and skip assets that opt out: the standard machine-readable way to express "do not train on this".

Each field takes an AiTrainingUse value:

ValueMeaning
"notAllowed"Use is not permitted (the default when a field is omitted)
"notAllowedByC2PA"Not permitted, asserted specifically per the C2PA constraint
"allowed"Use is permitted

Because the default is notAllowed, an assertion built with no arguments is already a full opt-out.

import { cawgTrainingMiningAssertion } from "@limboai/verifox-sdk-issuer/assertions";

// Explicit opt-out of generative training; allow inference
const training = cawgTrainingMiningAssertion({
aiInference: "allowed",
aiGenerativeTraining: "notAllowed",
});

Building assertions

Mix raw objects and typed helpers freely in the same array:

sign-with-assertions.ts
import {
cawgMetadataAssertion,
cawgTrainingMiningAssertion,
} from "@limboai/verifox-sdk-issuer/assertions";

const assertions = [
// cawg.metadata: Dublin Core title and description
cawgMetadataAssertion({ title: "Sunset over the bay" }),
// cawg.training-mining: AI training and mining permissions (default: notAllowed)
cawgTrainingMiningAssertion({ aiGenerativeTraining: "notAllowed" }),
// any other allowlisted label, as a raw { label, data }
{ label: "stds.schema-org.CreativeWork", data: { "@type": "ImageObject" } },
];

const { sidecar } = await sdk.sign(edited, "photo.jpg", {
origin: { sourceType: "digitalCapture" },
actions: [{ kind: "published" }],
assertions,
}, { storage: { mode: "embedded" } });

See also