A photo straight from a phone usually carries more than the picture. There are GPS coordinates precise enough to find a front door, the device make and model, the capture time to the second and the software version. Images from AI tools can also carry the full generation prompt. None of it shows on screen, and all of it goes wherever the file goes.
Removing it is easy. Removing it without damaging the image is where most tools fall short. This guide explains the difference and shows how to inspect and strip metadata losslessly from JPEG, PNG and WebP files, using the Metadata API or ExifTool on your own machine.
What hides in an image file
| Where | What it can contain |
|---|---|
| EXIF | Camera make and model, lens, settings, capture and edit times, orientation, GPS latitude and longitude, software |
| XMP | Editing history, ratings, keywords, IPTC fields such as creator and DigitalSourceType (which can mark AI images) |
| IPTC / Photoshop (APP13) | Captions, creator, copyright, location names |
| PNG text chunks | Free-form text; Stable Diffusion stores its full prompt in parameters, ComfyUI its prompt and workflow |
| C2PA manifest | Signed provenance: which tool created or edited the image, and how |
| Trailing data | Bytes after the end of the image, such as the video part of some "motion photos" |
| ICC profile | Colour space information that keeps colours accurate (worth keeping) |
Why "re-save" tools lose quality
Many metadata removers, including most browser-based ones, open the image, draw it and save a new file. For a JPEG, that is a full decode and re-encode: the compression runs again and throws away detail again. It is a small loss each time, but it adds up, and it can also change colour if the ICC profile is dropped.
A lossless cleaner works on the file structure instead. It walks the JPEG segments, PNG chunks or WebP chunks, drops the ones that hold metadata and copies everything else, including the compressed image data, byte for byte. The decoded pixels before and after are identical.
Step 1: Inspect what the image reveals
curl -X POST https://api.opencorpo.com/v1/metadata/image/inspect \
-H "X-API-Key: $OPENCORPO_API_KEY" \
-F "file=@IMG_2041.jpg"{
"format": "jpeg",
"width": 4032,
"height": 3024,
"metadata": {
"exif": {
"Make": "Apple",
"Model": "iPhone 15 Pro",
"Software": "17.4.1",
"Orientation": 6,
"DateTime": "2026:10:12 14:03:51",
"GPS": {
"GPSLatitudeRef": "N", "GPSLatitude": ["48.0", "51.0", "29.6"],
"GPSLongitudeRef": "E", "GPSLongitude": ["2.0", "17.0", "40.2"]
}
},
"has_gps_location": true,
"xmp_present": false,
"xmp_excerpt": null,
"png_text": {},
"c2pa": null,
"icc_profile": true
},
"ai_signals": [],
"removable": ["EXIF (APP1)"],
"billing": { "price_key": "metadata.image", "charged_eur": "0.003000", "free_trial": false }
}has_gps_location is the field to alert on. removable lists exactly what a clean would drop. ai_signals lists places where the file declares itself AI-generated: a C2PA digital source type, an XMP DigitalSourceType, a generator name in EXIF, or a prompt in a PNG text chunk. These are findings, not a verdict on how the image was made.
Step 2: Clean it
curl -X POST https://api.opencorpo.com/v1/metadata/image/clean \
-H "X-API-Key: $OPENCORPO_API_KEY" \
-F "file=@IMG_2041.jpg"{
"removed": ["EXIF (APP1)"],
"original_size_bytes": 2817533,
"output": {
"id": "md_d3d7a43f627002d6b93d",
"size_bytes": 2803117,
"content_type": "image/jpeg",
"download_url": "https://...",
"download_url_expires_in": 3600
},
"pixels_modified": false,
"billing": { "price_key": "metadata.image", "charged_eur": "0.003000", "free_trial": false }
}The ICC colour profile is kept by default so colours do not shift. Send keep_color_profile=false to drop it too. The cleaned file is available from download_url for an hour and deleted after 24 hours.
What gets removed, by format:
- JPEG: EXIF and XMP (APP1), IPTC (APP13), C2PA/JUMBF (APP11), MPF secondary images, other application segments, comments, and anything after the end-of-image marker. JFIF, Adobe colour info and the ICC profile are kept.
- PNG: text chunks (
tEXt,iTXt,zTXt),eXIf,tIME, C2PA (caBX) and other ancillary chunks. Chunks that affect rendering, such as transparency, gamma and animation, are kept. - WebP:
EXIF,XMPandC2PAchunks, with the header flags corrected.
Step 3: Check the result
With ExifTool:
exiftool -a -G1 -s IMG_2041-clean.jpgOnly file-level information (size, dimensions, encoding) and the ICC profile should remain. To prove nothing visual changed, compare the decoded pixels in Python:
from PIL import Image
a = Image.open("IMG_2041.jpg")
b = Image.open("IMG_2041-clean.jpg")
print(a.tobytes() == b.tobytes()) # True: identical pixelsClean a whole folder (Python)
import os
import pathlib
import requests
API = "https://api.opencorpo.com"
HEADERS = {"X-API-Key": os.environ["OPENCORPO_API_KEY"]}
def clean_image(src: pathlib.Path, dst_dir: pathlib.Path) -> list[str]:
with src.open("rb") as fh:
r = requests.post(f"{API}/v1/metadata/image/clean", headers=HEADERS,
files={"file": (src.name, fh)}, timeout=60)
body = r.json()
if not r.ok:
raise RuntimeError(f"{src.name}: {body['error']['code']}")
out = requests.get(body["output"]["download_url"], timeout=60)
out.raise_for_status()
(dst_dir / src.name).write_bytes(out.content)
return body["removed"]
src_dir, dst_dir = pathlib.Path("photos"), pathlib.Path("photos-clean")
dst_dir.mkdir(exist_ok=True)
for path in sorted(src_dir.iterdir()):
if path.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp"}:
print(path.name, "->", clean_image(path, dst_dir) or "nothing to remove")Clean user uploads (Node.js 20+)
A common place to do this is the upload handler, before a user's photo is stored or shown to anyone else:
const API = "https://api.opencorpo.com";
export async function stripImageMetadata(bytes, filename) {
const form = new FormData();
form.append("file", new Blob([bytes]), filename);
const res = await fetch(`${API}/v1/metadata/image/clean`, {
method: "POST",
headers: { "X-API-Key": process.env.OPENCORPO_API_KEY },
body: form,
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const cleaned = await fetch(body.output.download_url);
return Buffer.from(await cleaned.arrayBuffer()); // store this instead of the original
}Prefer to do it locally? Use ExifTool
ExifTool also edits metadata without re-encoding, and it is the right tool if you can run it where the files are:
# Remove all metadata but keep the colour profile
exiftool -all= -tagsfromfile @ -icc_profile photo.jpg
# Remove only the GPS tags
exiftool -gps:all= photo.jpgThe API makes more sense when you cannot install binaries (serverless functions, managed platforms), when you want one interface for images, video and text, or when you want a machine-readable report of what was found and removed for each file.
If you publish AI images: clean first, then sign
Cleaning removes C2PA manifests along with everything else. If you mark AI-generated images for the EU AI Act, clean the raw output first, then add Content Credentials. The other order removes the credentials you just added.
Limits
- Not a watermark remover. Cleaning never touches pixels or audio, so watermarks embedded in the image data, such as SynthID or OpenCorpo's own, survive by design. Do not use it to remove AI-generation disclosures you are legally required to keep; our terms forbid it.
- JPEG, PNG and WebP only, up to 20 MB. HEIC, AVIF, TIFF and RAW files are not supported.
- Orientation. Removing EXIF removes the Orientation tag, so phone photos stored in sensor orientation can display sideways. Rotate the pixels first if that matters.
- Extras attached to the main image are removed. For Ultra HDR photos with a gain map, or motion photos with an appended video, the main image is kept bit for bit, but the HDR gain map or video part is dropped.
- Pixels can still give you away. Street signs, landmarks, reflections and faces are part of the image, not metadata.
- Short retention. Cleaned files are deleted after 24 hours; the download link lasts an hour.
Frequently asked questions
Does removing EXIF data reduce image quality?
Not when it is done at the container level. The compressed image data is copied byte for byte and only metadata segments are dropped. Tools that open and re-save a JPEG do lose quality, because they decode and re-encode it.
Does this remove the GPS location from iPhone photos?
Yes for JPEG, PNG and WebP. HEIC, the default iPhone camera format, is not supported; most sharing paths convert to JPEG, and a JPEG export can be cleaned.
Does it remove AI watermarks such as SynthID?
No. Pixel-level watermarks such as SynthID or OpenCorpo's own live in the image data, which cleaning never touches. The tool removes metadata only, and must not be used to remove AI-generation disclosures you are required to keep.
Do social networks remove EXIF data anyway?
Many platforms strip some or all metadata on upload, but behaviour varies and changes over time, and sending a photo as a file or document usually keeps the original bytes. Clean before sharing if location matters.
Why does my cleaned photo appear rotated?
Phone cameras often store the picture in sensor orientation and add an EXIF Orientation tag telling viewers to rotate it. Removing EXIF removes that tag. Rotate the image itself before cleaning if you need it upright everywhere.
How much does it cost?
€0.003 per image for each inspect or clean call. Your first 3 Metadata API calls are free.