# C2PA Content Credentials Checker - Is This Image AI-Labeled? (`that_red_bird/content-credentials-checker`) Actor

Check images and videos in bulk for C2PA Content Credentials and IPTC AI labels: AI-generated flag, issuer, edit history and signature validity. Offline verification, no API key. Built for EU AI Act labelling checks. No credentials is not proof of human-made.

- **URL**: https://apify.com/that_red_bird/content-credentials-checker.md
- **Developed by:** [mohamed alaya](https://apify.com/that_red_bird) (community)
- **Categories:** AI, Developer tools, Social media
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 asset checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## C2PA Content Credentials Checker - Is This Image AI-Labeled?

Give it image or video URLs. It reads the **C2PA Content Credentials** and **IPTC/XMP AI labels** inside each file and tells you whether it is marked as AI-generated, who signed it, what edits are recorded and whether the signature holds up.
Built for publishers, ad networks, marketplaces and trust and safety teams who need to check AI labels in bulk (the EU AI Act's Article 50 labelling duty applies from August 2026). The Store already has tools that strip these labels; this one reads and verifies them.

Verification runs offline with the open-source C2PA library, so there is no API key and nothing is sent to a third party except the download of the file itself.

### Input examples

**1. A few URLs**

```json
{ "urls": ["https://example.com/photo1.jpg", "https://example.com/clip.mp4"] }
```

**2. Images from another scraper's dataset** (pick the dataset in the form, or pass its id)

```json
{ "datasetId": "YOUR_DATASET_ID", "datasetField": "displayUrl", "onlyAiLabeled": true }
```

**3. Everything, without the trust-list check, no edit history**

```json
{ "urls": ["https://example.com/a.png"], "checkTrust": false, "includeEditHistory": false }
```

Run with no input to see a demo on bundled sample files (an AI image with a C2PA manifest, an image with only an IPTC AI label, an unlabeled image) plus one public C2PA test image.

### Input guide

| Field | What it does |
|---|---|
| `urls` | Direct links to JPEG, PNG, WebP, AVIF, HEIC, TIFF, GIF, MP4, MOV, PDF, WAV, MP3 and other files C2PA supports. |
| `datasetId`, `datasetField` | Read media URLs from an existing dataset. Leave the field empty to auto-detect image and video URLs. |
| `checkTrust` | Check the signer against the official C2PA trust list (default on). |
| `includeEditHistory` | Include recorded actions (created, edited, filtered...) and the software behind them. |
| `onlyAiLabeled` | Output only files that carry an AI-generated marking. Other files are not charged. |
| `maxFileMb` | Skip files bigger than this (default 25 MB). Whole files are downloaded because manifests can sit at the end of a video. |

### Output

| Field | Meaning |
|---|---|
| `status` | `AI_LABELED`, `CREDENTIALS_NO_AI_MARK`, `INVALID_CREDENTIALS`, `NO_CREDENTIALS_AI_HINTS` or `NO_CREDENTIALS` |
| `aiLabeled`, `aiSourceClass` | True when a C2PA action or IPTC/XMP `DigitalSourceType` says trainedAlgorithmicMedia or compositeWithTrainedAlgorithmicMedia |
| `labelSources` | Exactly which marking was found, for example `C2PA c2pa.created = trainedAlgorithmicMedia` |
| `hasC2pa`, `c2paValidationState` | Whether a manifest exists and its state: `Valid`, `Trusted` or `Invalid` |
| `signatureValid`, `issuerTrusted` | Cryptographic validity, and whether the signer is on the C2PA trust list |
| `issuer`, `signerName`, `signedAt`, `claimGenerator` | Who signed it, when, and with which tool |
| `editHistory` | Recorded actions with software agent and time |
| `metadataHints` | Weak hints such as a generator named in `CreatorTool` or Stable Diffusion parameters in a PNG |
| `note` | One-sentence plain-English reading of the result |

Sample row:

```json
{
  "type": "asset", "url": "https://example.com/render.jpg", "mimeType": "image/jpeg",
  "status": "AI_LABELED", "aiLabeled": true, "aiSourceClass": "ai_generated",
  "labelSources": ["C2PA c2pa.created = trainedAlgorithmicMedia"],
  "hasC2pa": true, "c2paValidationState": "Trusted", "signatureValid": true, "issuerTrusted": true,
  "issuer": "Example Imaging CA", "claimGenerator": "Example Image Generator 2.1",
  "editHistory": [{ "action": "c2pa.created", "digitalSourceType": "trainedAlgorithmicMedia", "softwareAgent": null, "when": null }]
}
```

### Use it with

- **Instagram / TikTok / Facebook scrapers:** run the scraper, then point `datasetId` here and set `datasetField` to the image or video URL field. Note that social networks strip metadata on upload, so check the original files where you can.
- **Ad and marketplace review queues:** run on creative URLs before approval and route `AI_LABELED` and `INVALID_CREDENTIALS` rows to a human.
- **Fake Reference Checker / AI Answer Link Checker:** companion Actors for checking AI-written text.

### FAQ

**Does `NO_CREDENTIALS` mean a human made it?** No. Credentials are optional and most platforms remove them when they re-encode a file. It only means this file carries none.

**Does it detect AI images without labels?** No. It reads declared labels; it is not a pixel-level AI detector and it does not read invisible watermarks such as SynthID.

**What does "issuerTrusted" use?** The official C2PA trust list (bundled, refreshed from the C2PA conformance repository at the start of each run). Test and self-signed certificates show as valid signatures from an untrusted issuer.

**Is the file stored?** No. It is downloaded into memory, inspected and discarded.

### Honest limits

- Only embedded manifests and IPTC/XMP markings are read. Remote (cloud-hosted) manifests are followed only when the library can fetch them.
- URLs must point straight at the file; web pages are not scraped for images. Some CDNs block data-centre IPs and come back as error rows.
- The EU AI Act wording is informational; this Actor is not a compliance certificate.

### Price

Pay per event: **$0.002 per file checked** (`asset-checked`). 500 images cost **$1.00**. Files that fail to download or cannot be read are free.

# Actor input Schema

## `urls` (type: `array`):

Direct links to image or video files (JPEG, PNG, WebP, AVIF, HEIC, TIFF, GIF, MP4, MOV and others C2PA supports). One per line. Leave this and the dataset empty to run a built-in demo.

## `datasetId` (type: `string`):

Optional. Pick a dataset from another Actor run (for example an Instagram, TikTok or Google Maps scraper). Every image or video URL found in its items is checked.

## `datasetField` (type: `string`):

Optional. Field name that holds the media URL in the dataset items, for example displayUrl or images. Dot paths work (media.url). Leave empty to detect image and video URLs automatically.

## `checkTrust` (type: `boolean`):

Validate the signing certificate against the official C2PA trust list. When off, a valid signature from any certificate is reported as valid but never as trusted.

## `includeEditHistory` (type: `boolean`):

Add the list of recorded actions (created, edited, filtered, converted) with the software that did them.

## `onlyAiLabeled` (type: `boolean`):

Skip rows for files that carry no AI-generated marking. Skipped files are not charged.

## `maxFileMb` (type: `integer`):

Files larger than this are skipped with an error row. The whole file is downloaded because C2PA manifests can sit at the end of video files.

## `maxItems` (type: `integer`):

Upper bound on how many files are checked in one run (hard limit 2000).

## `concurrency` (type: `integer`):

How many files are downloaded and inspected at the same time. Higher values use more memory.

## Actor input object example

```json
{
  "urls": [],
  "datasetField": "",
  "checkTrust": true,
  "includeEditHistory": true,
  "onlyAiLabeled": false,
  "maxFileMb": 25,
  "maxItems": 200,
  "concurrency": 4
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `downloadCsv` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `count` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [],
    "datasetField": "",
    "checkTrust": true,
    "includeEditHistory": true,
    "onlyAiLabeled": false,
    "maxFileMb": 25,
    "maxItems": 200,
    "concurrency": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("that_red_bird/content-credentials-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": [],
    "datasetField": "",
    "checkTrust": True,
    "includeEditHistory": True,
    "onlyAiLabeled": False,
    "maxFileMb": 25,
    "maxItems": 200,
    "concurrency": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("that_red_bird/content-credentials-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [],
  "datasetField": "",
  "checkTrust": true,
  "includeEditHistory": true,
  "onlyAiLabeled": false,
  "maxFileMb": 25,
  "maxItems": 200,
  "concurrency": 4
}' |
apify call that_red_bird/content-credentials-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,that_red_bird/content-credentials-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9fVDfDaGY9goagzBn/builds/juxR88MqNRrONsIsk/openapi.json
