# Image Metadata Remover — EXIF, C2PA & AI Label Stripper (`andrew_babo/ai-footprint-remover`) Actor

Bulk image metadata remover. Remove EXIF, GPS, IPTC, XMP, ICC, Stable Diffusion prompt chunks, C2PA Content Credentials and the AI-generated label from photos. Lossless by default, optional pixel scrub against classic invisible watermarks.

- **URL**: https://apify.com/andrew\_babo/ai-footprint-remover.md
- **Developed by:** [Andrew Babo](https://apify.com/andrew_babo) (community)
- **Categories:** AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Image Metadata Remover — EXIF, C2PA & AI Label Stripper

Bulk image metadata remover for Apify. Remove metadata from photos and
images — EXIF, GPS, IPTC, XMP, ICC, Stable Diffusion prompt chunks, C2PA
Content Credentials and the "generated by AI" label — in one run.

The default mode is **lossless**: the decoded pixels of the output are
bit-identical to the input (verified, mean delta `0`). Only the metadata
containers are removed.

### What metadata does it remove?

| Layer | Examples | Handled |
|---|---|---|
| EXIF | GPS coordinates, camera Make/Model, serial numbers, timestamps, Software | Yes |
| IPTC | Caption, credit, byline, copyright | Yes |
| XMP | Creator, rights, editing history, `DigitalSourceType` (the AI label) | Yes |
| PNG text chunks | Stable Diffusion / ComfyUI / A1111 prompt, seed, model, sampler | Yes |
| WebP / HEIC / AVIF boxes | EXIF and XMP RIFF/ISOBMFF chunks | Yes |
| C2PA / JUMBF | Content Credentials manifests and signatures (APP11 / `jumb` boxes) | Yes |
| ICC profile | Optional — keep it with `keepColorProfile` | Yes |
| Embedded thumbnails | The small preview that often survives naive strippers | Yes |
| Classic invisible watermarks | DWT-DCT style frequency-domain marks | `scrub` mode |
| SynthID, Stable Signature, Tree-Ring | Model-space watermarks | **No — flagged, not removed** |

Supports JPEG, PNG, WebP, HEIC, AVIF, TIFF and GIF.

### How to remove metadata from photos in bulk

Send a list of image URLs and pick a mode. One dataset record per image is
returned, plus the cleaned file in the run's key-value store.

```json
{
  "imageUrls": ["https://example.com/photo.jpg"],
  "mode": "clean",
  "outputFormat": "auto",
  "concurrency": 5
}
```

Images can also come in as `imagesBase64`, or as `keyValueStoreKeys` from an
existing key-value store (`sourceKeyValueStoreId`).

Three modes:

- **inspect** — report only. Lists every layer, every tag, whether a C2PA
  manifest or an AI label is present. The file is not modified.
- **clean** (default) — remove all metadata and C2PA. Pixels untouched.
- **scrub** — clean, plus a pixel-level pass (re-encode, resize round-trip,
  light noise, optional border crop) that destroys classic invisible
  watermarks.

### Remove the AI-generated label and C2PA Content Credentials

Modern AI generators tag their output. The IPTC/XMP
`DigitalSourceType = trainedAlgorithmicMedia` field marks an image as
AI-made, and C2PA Content Credentials embed a signed provenance manifest
(JUMBF boxes / APP11 segments) that can name the generator, the account and
the full edit history.

This Actor strips both: the AI label tags and the entire C2PA manifest. The
manifest is bound to the exact byte sequence of the file, so dropping it
invalidates the signature and removes the provenance chain outright — no
C2PA library needed, no pixel touched.

For classic invisible watermarks (DWT-DCT frequency-domain marks), `scrub`
mode applies a pixel-level attack. Verified against a real DWT-DCT
watermark: decode accuracy falls from 100 % to 42 %, where random guessing
sits at 50 % — nothing recoverable. For scrub runs, set `outputFormat` to
`webp` or `jpeg`; PNG cannot compress the added noise and the file grows a
lot.

### Does it change my pixels?

No, not in the default `clean` mode. The decoded image is bit-identical
before and after (mean/max pixel delta `0` across the test set); only the
metadata containers are dropped.

`scrub` mode intentionally changes pixels — that is how it breaks invisible
watermarks. Every scrub record reports the exact pixel mean/max delta and
byte sizes so you can see how much the image changed.

### Output

One dataset record per image with the layers found before and after, the
full tag dump before and after, `aiLabelRemoved`, `c2paRemoved`, `clean`,
`pixelChanged`, pixel mean/max delta, byte sizes, warnings, and a public
link to the cleaned file in the run's key-value store.

### Limitations

- Google SynthID, Meta's Stable Signature and Tree-Ring watermarks are
  embedded in the generative model itself, not in the file. There is no
  cheap CPU method to remove them, so this Actor does not pretend to. When
  the source metadata points at such a generator, the record carries an
  explicit warning instead.
- `clean` deliberately does not touch pixels, so any pixel-domain watermark
  survives it — use `scrub` for those.

### FAQ

**Does it reduce image quality?**
No. The default clean mode is lossless — pixels are bit-identical. Scrub
mode changes pixels on purpose and reports the exact difference.

**Can it remove metadata from AI-generated images?**
Yes. It removes the IPTC/XMP AI label (`DigitalSourceType`), Stable
Diffusion / ComfyUI prompt chunks, and C2PA Content Credentials left by
generators such as Adobe Firefly.

**Can it remove the Gemini / SynthID watermark?**
No — SynthID lives in the model, not the file, and no cheap removal exists.
The Actor flags a warning when an image likely carries it instead of
claiming a fake removal.

**What does it cost?**
Fractions of a cent per image on the Apify platform — roughly $0.00002 per
image at 1 GB RAM, plus any Actor pricing if set.

Full measurements: [`docs/ai-footprint-remover-poc.md`](docs/ai-footprint-remover-poc.md).

# Actor input Schema

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

Direct links to the images to process. JPEG, PNG, WebP, HEIC, AVIF, TIFF and GIF are supported.

## `imagesBase64` (type: `array`):

Images as base64 strings or data URLs. Useful when calling the Actor from your own backend.

## `keyValueStoreKeys` (type: `array`):

Keys of images already stored in a key-value store.

## `sourceKeyValueStoreId` (type: `string`):

ID or name of the key-value store holding the keys above. Defaults to the run's own store.

## `mode` (type: `string`):

inspect = report only, nothing is modified. clean = remove all metadata and C2PA while keeping pixels byte-identical. scrub = clean plus pixel transforms that break classic invisible watermarks.

## `keepColorProfile` (type: `boolean`):

Keep the embedded ICC profile so colours render exactly as before. The profile can carry a software name.

## `outputFormat` (type: `string`):

auto keeps the input format. Choosing a format forces a re-encode, which also destroys any provenance manifest.

## `reencodeQuality` (type: `integer`):

JPEG/WebP quality used whenever the image has to be re-encoded (scrub mode, format change, or containers without a lossless path).

## `resizeRoundTrip` (type: `number`):

Scrub mode: shrink to this fraction of the original size and scale back up. The 0.82 default is the level verified to destroy a DWT-DCT watermark; raise it towards 1 to keep more detail at the cost of watermark removal.

## `noiseAmplitude` (type: `integer`):

Scrub mode: maximum per-channel random shift added to every pixel (0-8). 4 is the verified default and stays visually invisible.

## `cropBorderPx` (type: `integer`):

Scrub mode: trim this many pixels from each edge to break alignment-sensitive watermarks.

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

Images larger than this are skipped with an error entry.

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

How many images to process in parallel.

## `storeOutput` (type: `boolean`):

Save the cleaned files in the run's key-value store and return download links. Turn off if you only need the report.

## `requestTimeoutSecs` (type: `integer`):

Timeout for downloading a single image URL.

## Actor input object example

```json
{
  "imageUrls": [],
  "mode": "clean",
  "keepColorProfile": false,
  "outputFormat": "auto",
  "reencodeQuality": 92,
  "resizeRoundTrip": 0.82,
  "noiseAmplitude": 4,
  "cropBorderPx": 2,
  "maxFileSizeMb": 25,
  "concurrency": 5,
  "storeOutput": true,
  "requestTimeoutSecs": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `STATS` (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": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("andrew_babo/ai-footprint-remover").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": [] }

# Run the Actor and wait for it to finish
run = client.actor("andrew_babo/ai-footprint-remover").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": []
}' |
apify call andrew_babo/ai-footprint-remover --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,andrew_babo/ai-footprint-remover"
        }
    }
}

```

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/T1LrKTS7WlG5uiuqi/builds/RddDDn7QpSBPUIbm4/openapi.json
