# AI Image Metadata Checker – C2PA, IPTC & EXIF Detector (`fast_data_asap/ai-image-metadata-detector`) Actor

Check images for AI-generation metadata: C2PA / Content Credentials manifests, IPTC DigitalSourceType (trainedAlgorithmicMedia), Midjourney, DALL·E, Firefly, Stable Diffusion & ComfyUI tags, EXIF camera data. Scan image URLs or whole web pages. EU AI Act Art. 50 labelling helper.

- **URL**: https://apify.com/fast_data_asap/ai-image-metadata-detector.md
- **Developed by:** [Fast Data](https://apify.com/fast_data_asap) (community)
- **Categories:** AI, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 image analyseds

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

## AI Image Metadata & Content Credentials Checker (C2PA, IPTC, EXIF)

Find out what an image **says about itself**. This actor downloads images (from direct URLs or from whole web pages) and reads the metadata embedded in each file:

- **C2PA / Content Credentials** manifests (JUMBF in JPEG APP11, PNG `caBX` chunk, WebP `C2PA` chunk, AVIF/HEIC): claim generator, signer, actions such as `c2pa.created`, the `digitalSourceType` and the validation state. Parsed with the official open-source `c2pa` library, with a built-in fallback parser.
- **IPTC / XMP** `Iptc4xmpExt:DigitalSourceType` (`trainedAlgorithmicMedia`, `compositeWithTrainedAlgorithmicMedia`, `algorithmicMedia`, `algorithmicallyEnhanced`, `compositeSynthetic`, `digitalCapture` ...), `xmp:CreatorTool`, IPTC credit line (e.g. "Made with Google AI").
- **AI generator parameters** in PNG text chunks and EXIF UserComment: Stable Diffusion / AUTOMATIC1111 / Forge `parameters`, ComfyUI `prompt` / `workflow`, InvokeAI, Fooocus, NovelAI. Only a yes/no flag and the generator name are returned – **never the prompt**.
- **Known AI software tags**: Midjourney, OpenAI (DALL·E / ChatGPT), Adobe Firefly, Google (Imagen / Gemini), Stable Diffusion, Leonardo.Ai, Ideogram, FLUX, Microsoft Designer / Bing Image Creator, NovelAI, Runway, Krea, Playground, Grok, Canva.
- **EXIF**: camera make and model, software, original capture date and whether GPS data is present (**GPS coordinates are never returned**).

One flat row per image with an `aiLikelihood` of `none`, `weak` or `strong`, the list of signals behind it and a plain-language note.

### Who it is for

- **Shops, publishers, agencies and marketing teams** preparing for the transparency rules for AI-generated content (EU AI Act, Art. 50) who need an inventory of which images on their sites already carry AI markers.
- **Content moderation, trust & safety and newsrooms** who want a quick provenance check of incoming images.
- **SEO and web teams** auditing image metadata (stripped metadata, leftover camera data, GPS present) across many pages.
- **Developers and AI agents** who need a cheap, deterministic metadata check via API, n8n, Make or MCP.

### Why this actor

- Reads **C2PA Content Credentials and IPTC digital source type together**, the two standards that Adobe, OpenAI, Google, Microsoft, Midjourney, Meta and camera makers actually use.
- **Scans whole pages**: give a product page or blog post and it collects `<img>`, `srcset`, `<picture>`, `og:image` and `twitter:image`.
- **Privacy by design**: no GPS coordinates, no prompts, no personal data in the output.
- **Transparent rules** instead of a black-box score (see below), and an honest note when nothing is found.
- **Cheap**: pay only per image successfully analysed; failed downloads are free.

### How aiLikelihood is decided

| Value | Rule |
|---|---|
| `strong` | A C2PA manifest or IPTC/XMP metadata declares `trainedAlgorithmicMedia`, `compositeWithTrainedAlgorithmicMedia` or `algorithmicMedia`; **or** the C2PA claim generator / software agent is a known AI generator (e.g. Adobe Firefly, ChatGPT); **or** the file contains AI generator parameter chunks (Stable Diffusion `parameters`, ComfyUI workflow, InvokeAI, NovelAI). |
| `weak` | Only a software or keyword tag (EXIF Software, XMP CreatorTool, IPTC credit, PNG text) names a known AI tool, or the digital source type is `algorithmicallyEnhanced` / `compositeSynthetic`. |
| `none` | No AI marker in the embedded metadata. A C2PA manifest may still be present (e.g. a camera or an editing app signed it). |

`metadataStripped` is `true` when the file has no EXIF, XMP, IPTC, C2PA or PNG text metadata at all.

#### Important limits

- This actor reads **embedded metadata only**. It does **not** perform pixel-level AI detection and cannot see invisible watermarks such as Google SynthID.
- **Metadata absence does not prove that an image is not AI-generated.** Many CMS, CDNs, image optimisers and social networks strip metadata. Metadata can also be added or edited by anyone; C2PA signatures make tampering detectable, and the `c2paValidation` field shows the validation result.
- **Not legal advice.** Art. 50 of the EU AI Act (Regulation (EU) 2024/1689) sets transparency obligations for AI-generated or manipulated content, including machine-readable marking by providers and disclosure of deepfakes by deployers. Whether a specific image must be labelled depends on its context; use this tool as an inventory and evidence helper and consult your legal advisers.

### Input

| Field | Description |
|---|---|
| `imageUrls` | Direct image links (JPEG, PNG, WebP, AVIF, HEIC, TIFF, GIF). |
| `pageUrls` | Web pages to scan for images. |
| `maxImagesPerPage` | Limit per page (default 20). |
| `maxFileSizeMb` | Skip larger files (default 25 MB). |
| `maxConcurrency` | Parallel downloads (default 5). |
| `proxyConfiguration` | Optional Apify proxy. |

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
    "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg"
  ],
  "pageUrls": ["https://example.com/blog/post-with-images"],
  "maxImagesPerPage": 20
}
```

### Output

Real rows from a test run (C2PA test image from the c2pa-org repository and a Canon camera JPEG):

```json
{
  "imageUrl": "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
  "pageUrl": null,
  "format": "jpeg",
  "sizeBytes": 132518,
  "width": 2048,
  "height": 1365,
  "aiLikelihood": "strong",
  "aiSignals": ["c2pa:manifest_present", "c2pa:digitalSourceType=algorithmicMedia"],
  "aiGenerator": null,
  "c2paPresent": true,
  "c2paClaimGenerator": "make_test_images/0.33.1 c2pa-rs/0.33.1",
  "c2paSigner": "C2PA Test Signing Cert",
  "c2paActions": ["c2pa.created"],
  "c2paValidation": "Valid",
  "digitalSourceType": "algorithmicMedia",
  "software": null,
  "cameraMake": null,
  "cameraModel": null,
  "gpsPresent": false,
  "exifPresent": false,
  "xmpPresent": false,
  "iptcPresent": false,
  "generatorParametersPresent": false,
  "metadataStripped": false,
  "note": "Embedded metadata declares the image as AI/algorithmically generated or AI-edited. Check the context before labelling.",
  "status": "ok"
}
```

```json
{
  "imageUrl": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg",
  "format": "jpeg",
  "width": 100,
  "height": 68,
  "aiLikelihood": "none",
  "aiSignals": [],
  "c2paPresent": false,
  "software": "GIMP 2.4.5",
  "cameraMake": "Canon",
  "cameraModel": "Canon EOS 40D",
  "dateTimeOriginal": "2008:05:30 15:56:01",
  "gpsPresent": false,
  "metadataStripped": false,
  "note": "No AI marker in the embedded metadata. Metadata absence does not prove an image is not AI-generated.",
  "status": "ok"
}
```

Other `status` values: `http_404`, `http_403`, `timeout`, `too_large`, `not_an_image`, `unsupported_format_svg`, `download_failed: ...`, and for pages `no_images_found` / `page_fetch_failed`. These rows are free.

### Pricing

Pay per event: **$0.0015 per image analysed** ($1.50 per 1,000 images). Failed downloads, unsupported files and page rows are not charged. Platform usage is minimal (a 3-image run takes a few seconds at 512 MB).

### Use via API, n8n, Make or MCP

**API** (run synchronously and get the dataset items):

```bash
curl -X POST "https://api.apify.com/v2/acts/fast_data_asap~ai-image-metadata-detector/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pageUrls": ["https://example.com/"], "maxImagesPerPage": 10}'
```

**n8n / Make / Zapier**: use the Apify node or app, choose this actor, pass the JSON input above and read the dataset items.

**MCP (Claude, Cursor, other AI agents)**: add the Apify MCP server with this actor as a tool:

```
https://mcp.apify.com?tools=fast_data_asap/ai-image-metadata-detector
```

Then ask e.g. "Check the images on https://example.com/shop for AI-generation metadata".

### FAQ

**Can it tell if an image was made by AI when there is no metadata?** No. It reports what the file declares. Use the result as one signal among others.

**Does it validate C2PA signatures?** Yes, when the manifest can be parsed with the c2pa library; `c2paValidation` contains the validation state or the validation issues (for example untrusted test certificates).

**Does it store the images?** No. Images are processed in memory and only the metadata summary is saved.

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to images (JPEG, PNG, WebP, AVIF, HEIC, TIFF, GIF). Each image is downloaded and its embedded metadata is checked.

## `pageUrls` (type: `array`):

Optional. Web pages (e.g. product pages, blog posts, landing pages). The actor collects images from <img>, srcset, <picture> and og:image / twitter:image tags and checks each one.

## `maxImagesPerPage` (type: `integer`):

Limit of images taken from each web page.

## `maxFileSizeMb` (type: `integer`):

Images larger than this are skipped (status too_large, not charged).

## `maxConcurrency` (type: `integer`):

How many images are downloaded in parallel.

## `proxyConfiguration` (type: `object`):

Optional. Usually not needed; images are fetched directly.

## Actor input object example

```json
{
  "imageUrls": [
    "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
    "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/CA.jpg",
    "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg"
  ],
  "maxImagesPerPage": 20,
  "maxFileSizeMb": 25,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `results` (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 = {
    "imageUrls": [
        "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
        "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/CA.jpg",
        "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fast_data_asap/ai-image-metadata-detector").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 = { "imageUrls": [
        "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
        "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/CA.jpg",
        "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fast_data_asap/ai-image-metadata-detector").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 '{
  "imageUrls": [
    "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/C.jpg",
    "https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/CA.jpg",
    "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg"
  ]
}' |
apify call fast_data_asap/ai-image-metadata-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fast_data_asap/ai-image-metadata-detector"
        }
    }
}
```

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/7JDiNaerlkcOOqQIF/builds/SuhZXUWHUnEJJSKDr/openapi.json
