New: try each tool in your browser, no account needed. Then one API key with 3 free tries of every API. Get your key →
Metadata5 min read

How to remove EXIF and GPS data from photos without losing quality

Most metadata removers re-save the image and lose quality. Here is how to see what a photo reveals (GPS location, device, software, AI prompts) and strip it losslessly, by API or with ExifTool, with code you can run.

OpenCorpo Team

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

bash
curl -X POST https://api.opencorpo.com/v1/metadata/image/inspect \
  -H "X-API-Key: $OPENCORPO_API_KEY" \
  -F "file=@IMG_2041.jpg"
json
{
  "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

bash
curl -X POST https://api.opencorpo.com/v1/metadata/image/clean \
  -H "X-API-Key: $OPENCORPO_API_KEY" \
  -F "file=@IMG_2041.jpg"
json
{
  "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, XMP and C2PA chunks, with the header flags corrected.

Step 3: Check the result

With ExifTool:

bash
exiftool -a -G1 -s IMG_2041-clean.jpg

Only file-level information (size, dimensions, encoding) and the ICC profile should remain. To prove nothing visual changed, compare the decoded pixels in Python:

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 pixels

Clean a whole folder (Python)

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:

javascript
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:

bash
# Remove all metadata but keep the colour profile
exiftool -all= -tagsfromfile @ -icc_profile photo.jpg

# Remove only the GPS tags
exiftool -gps:all= photo.jpg

The 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.