Short answer: there are two families of method, and they are not interchangeable. Re-saving the photo through an editor removes the metadata as a side effect of rewriting the file — it also re-encodes the pixels, so the picture you get back is not bit-for-bit the picture you put in. Stripping the segment deletes the metadata block in place and leaves every pixel exactly as it was. Both end up with no EXIF; only one leaves the photo untouched.
The part almost nobody warns you about: the check you run afterwards can lie. Some files carry their EXIF in a form that common readers do not recognise, and those readers will report no EXIF found while the GPS coordinates and the camera serial number are still sitting in the file. We measured that below, with the exact output.
Scope, stated first: this page is about file metadata — the tags a camera writes. It is not about AI watermarks. Claude's text watermark is a statistical pattern in how the model chose its words, not data stored in a file; Anthropic's own documentation says “nothing is added to the text and there are no hidden characters”. No EXIF remover touches it. What Claude does attach to the images it generates is a C2PA content credential, which is metadata and genuinely can be deleted. The two layers, explained →
EXIF is a block in the file header, ahead of the compressed picture. It carries the make and model of the camera, the lens, the exposure settings, the date and time to the second, the camera's body serial number, the artist or owner name the camera was configured with, and — if location services were on — GPS coordinates in decimal degrees. Many cameras also write a small JPEG copy of the picture into the same block so file browsers can show a preview without decoding the whole thing.
None of that is the photograph. That is why removing it can be done without touching a single pixel, and why the file usually gets smaller rather than blurrier.
Two tags are worth knowing before you delete anything, because they are not identifying data and they do affect how the picture looks:
Orientation = 6, and every viewer rotates on display. Delete the tag and the raw pixels are shown as stored, so the photo appears rotated 90 degrees. No pixel changed; the photo did.Before you pick a method, check the file. Most people do this with whatever image library or file property panel they have to hand, and that is where the trouble starts.
The specification puts a six-byte identifier — Exif\0\0 — in front of the EXIF block. Readers look for it. But some writers put the TIFF structure straight into the block with no identifier at all. The data is identical; the label is missing. A reader that searches for the identifier finds nothing and reports the file as clean.
We built two files that carry the same GPS coordinates, the same serial number and the same owner name. One writes the identifier, one does not. Same data, two answers:
That second file is not exotic. It is the form this site's cleaner was failing to recognise until a reader reported a batch of photos coming back sideways — the orientation was there, in a block nobody was reading. So: if a check tells you a file has no EXIF, confirm it with something that reads the block itself rather than looking for the label.
One source file, four results. The source is a 1,600 × 1,200 JPEG carrying GPS coordinates, a body serial number, an owner name, an embedded thumbnail and Orientation = 6. Every number in this table came out of a run on this machine, not out of a spec sheet.
| Method | Result | Pixels | What was left in the file |
|---|---|---|---|
| Nothing done (the source) | 130,121 B | baseline | GPS 37.789556, 122.419333 · serial AX1-4417-2026 · owner Alex Rivera · thumbnail 3,178 B |
| Re-save through a library, no EXIF handed over | 126,722 B | changed | nothing identifying — but see the next section |
| Strip the segment in place (this site's tool) | 126,473 B | byte-identical | Orientation 6, in a 34-byte block |
| Delete every APP1 segment by hand | 126,437 B | byte-identical | nothing — Orientation included, so an upright photo turns sideways |
The file sizes differ by a few hundred bytes and all four look the same in a file manager. The difference that matters is the third column.
Both end with a file that has no EXIF. They get there by different routes, and the route shows up in the picture.
Re-saving decodes the image and compresses it again. The compressed data that comes out is not the compressed data that went in — in our run the scan data changed from 044f4ea22577267b to cab64ad8c967ba79. That is not visible at a glance, but it is a second generation of compression on a photo that was already compressed once, and doing it repeatedly is how people end up with soft, slightly muddy files.
Stripping does not decode anything. The metadata lives in a segment ahead of the scan; deleting that segment and writing the rest back untouched leaves the compressed picture exactly as the camera encoded it. In our run the scan hash is unchanged, byte for byte. This is also why the stripped file is larger than the re-saved one here: keeping the original compression is worth more than the bytes saved by re-encoding.
If you are going to re-save anyway because you are resizing or editing the photo, this does not matter — you are already re-encoding. If the only thing you want is to remove EXIF data, re-saving is an expensive way to do it.
Delete the whole EXIF block and you delete Orientation with it. On a photo where Orientation was 1 — meaning the pixels are already stored the right way up — nothing happens. On a phone photo taken upright, where the pixels are stored sideways and Orientation is what tells the viewer to rotate them, the picture comes out rotated.
So a stripper has a choice: leave the photo alone and upright, or delete every last tag. This site rebuilds a 34-byte EXIF block holding that single tag and nothing else. It is the only metadata we write back, and it is not identifying data — it is a number from 1 to 8 that says which way up to hold the picture. (The full list of what gets dropped and what gets kept →)
Standard library only, nothing to install. Save as exif_check.py and point it at a file or a whole folder. It reads the EXIF block itself instead of asking a library to look for the identifier — which is the entire point, given the section above.
import os, struct, sys
NAMES = {271: "camera make", 272: "camera model", 274: "orientation",
305: "software", 315: "artist / owner", 33432: "copyright",
42033: "body serial number"}
def read_ifd(b, off, endian):
if off + 2 > len(b):
return {}, 0
n = struct.unpack(endian + "H", b[off:off + 2])[0]
out = {}
for i in range(min(n, 200)):
p = off + 2 + i * 12
if p + 12 > len(b):
break
tag, typ, cnt = struct.unpack(endian + "HHI", b[p:p + 8])
size = {1: 1, 2: 1, 3: 2, 4: 4, 5: 8, 7: 1}.get(typ, 1) * cnt
raw = b[p + 8:p + 12]
if size > 4:
vp = struct.unpack(endian + "I", raw)[0]
if vp + size > len(b):
continue
raw = b[vp:vp + size]
out[tag] = (typ, cnt, raw[:size])
nxt = struct.unpack(endian + "I", b[off + 2 + n * 12:off + 6 + n * 12])[0]
return out, nxt
def text(typ, cnt, raw, endian):
if typ == 2:
return raw.rstrip(b"\x00").decode("ascii", "replace")
if typ == 3 and cnt == 1:
return str(struct.unpack(endian + "H", raw)[0])
return ""
def dms(d, endian):
if len(d) < 24:
return None
total = 0.0
for i in range(3):
num, den = struct.unpack(endian + "II", d[i * 8:i * 8 + 8])
if den:
total += (num / den) / (60 ** i)
return total
def check(path):
b = open(path, "rb").read()
if b[:2] != b"\xff\xd8":
return "%-34s not a JPEG" % os.path.basename(path)
i = 2
while i < len(b) - 1:
if b[i] != 0xFF:
break
m = b[i + 1]
if m == 0xDA:
break
if m in (0xD8, 0xD9) or 0xD0 <= m <= 0xD7 or m == 0x01:
i += 2
continue
ln = struct.unpack(">H", b[i + 2:i + 4])[0]
p = b[i + 4:i + 2 + ln]
if m == 0xE1:
# accept both forms: "Exif\0\0" + TIFF, and a bare TIFF block
t = p[6:] if p[:6] == b"Exif\x00\x00" else p
if t[:4] == b"II*\x00":
endian = "<"
elif t[:4] == b"MM\x00*":
endian = ">"
else:
i += 2 + ln
continue
ifd0, nxt = read_ifd(t, struct.unpack(endian + "I", t[4:8])[0], endian)
found = []
for tag in (271, 272, 305, 315, 33432, 42033, 274):
if tag in ifd0:
v = text(ifd0[tag][0], ifd0[tag][1], ifd0[tag][2], endian)
if v:
found.append("%s %s" % (NAMES[tag], v))
if 34665 in ifd0:
sp = struct.unpack(endian + "I", ifd0[34665][2])[0]
sub, _ = read_ifd(t, sp, endian)
if 42033 in sub:
v = text(sub[42033][0], sub[42033][1], sub[42033][2], endian)
if v:
found.append("body serial number %s" % v)
if 34853 in ifd0:
gp = struct.unpack(endian + "I", ifd0[34853][2])[0]
g, _ = read_ifd(t, gp, endian)
lat, lon = dms(g[2][2], endian), dms(g[4][2], endian)
if lat and lon:
found.append("GPS %.6f, %.6f" % (lat, lon))
if nxt:
ifd1, _ = read_ifd(t, nxt, endian)
if 514 in ifd1:
found.append("thumbnail %d bytes"
% struct.unpack(endian + "I", ifd1[514][2])[0])
return "%-34s %s" % (os.path.basename(path),
", ".join(found) or "nothing identifying")
i += 2 + ln
return "%-34s no EXIF block" % os.path.basename(path)
if __name__ == "__main__":
files = []
for t in sys.argv[1:]:
if os.path.isdir(t):
files += [os.path.join(t, f) for f in sorted(os.listdir(t))
if f.lower().endswith((".jpg", ".jpeg"))]
else:
files.append(t)
for f in files:
print(check(f))
Running it over the four files from the table above prints this:
cropped-rot6.jpg camera make Aurora, camera model Aurora X100, software Aurora Camera 4.2,
artist / owner Alex Rivera, orientation 6, body serial number AX1-4417-2026,
GPS 37.789556, 122.419333, thumbnail 3178 bytes
01-pil-resave.jpg no EXIF block
03-strip-segments.jpg orientation 6
04-drop-all-app1.jpg no EXIF block
That third line is the one to look for: one tag left, on purpose, and no longer anything that identifies anyone.
This removes metadata. It does not remove anything that is part of the picture. A logo or a watermark burned into the pixels is image data, not a tag, and no header surgery reaches it.
It also cannot remove a statistical watermark. Those are not stored in the file — they are a property of how the text or image was generated. If you are here because you want Claude's watermark gone, read that first; the short version is that no tool does it, and any site promising otherwise is selling you something else.
The measurements on this page were taken on this machine with the tools available here. Methods we could not run — command-line ExifTool on a machine that does not have it, macOS Preview, phone apps, hosted services — are left out rather than guessed at. The numbers above are real output from real runs; we did not estimate any of them.
Drop the file into the cleaner on this site. It runs in your browser, so the photo never leaves your device, and it strips the metadata without re-encoding the picture. If you would rather not upload anything at all — even to yourself — the script further up this page does the same check locally, and the folder cleaner in this guide shows the batch form.
Often yes, but not because you asked it to — because re-encoding writes a new file and most editors do not carry the old metadata across. That is a side effect, not a guarantee: some editors do carry it across, and some only carry part of it. The cost is that you also re-compress the picture. In our test the re-saved file's scan data changed hash while a stripped file's did not.
Point a folder-wide script at it rather than opening files one at a time. The pattern that works is: walk the folder, filter to image extensions, run the strip on each file, then re-run the check over the folder to confirm. This page has a working folder script, including a dry-run mode so you can see what would change before it writes anything, and a pre-commit hook if the folder is a git repository.
Deleting it, no. Re-encoding to delete it, yes — slightly, and cumulatively. Removing a header block cannot degrade the picture, because the picture is not in that block. The quality loss people associate with metadata removal comes from the re-save, not from the removal.
Because the tool deleted the Orientation tag along with everything else. A phone held upright usually stores landscape pixels plus Orientation = 6, and viewers rotate on display. Remove the tag and the raw pixels are shown as stored, so the picture is rotated 90 degrees. Nothing about the image changed; the instruction for displaying it did. This is why the cleaner here rebuilds a 34-byte block containing that one tag.
Only if it processes the file in your own browser. Many sites upload your photo to their server first, which means the GPS coordinates and serial number you were trying to remove have just been handed to someone else — and you have no way to check whether the copy was deleted afterwards. You can test any site: open your browser's network panel before dropping the file in and look at where the request goes. If the photo is uploaded, the removal is not private.
For photos, three families: a browser tool that never uploads (like the one on this site), a command-line tool, or a scripting library. All three are fine if you verify the result afterwards. Videos are a separate job and this tool does not do them. Video metadata lives in a different container structure (the atoms in an MP4 or MOV), not in a JPEG header segment, so a photo stripper has nothing to work on. If a page promises one tool for both, check whether it actually rewraps the video rather than just claiming to.
The reliable fix is at the source rather than in an app afterwards: turn off the camera's location permission and it stops writing GPS coordinates into new photos in the first place. For photos you already have, run them through a stripper before sharing. We have not tested Android camera apps on this machine, so we are not going to name one — and any list you find will be out of date within a year. What does not go out of date is the check: strip, then run the script above and confirm it prints nothing identifying.
That is a different operation from removing it, and it is worth being clear about which one you want. Stripping deletes the fields. Randomising writes different values in their place — a fake camera model, a fake serial number, a different date. This site deletes; it does not fabricate. If your goal is to stop one account being tied to another, deletion is the stronger option, because a randomised value is still a value that can be correlated, and a wrong date can break the sorting in whatever you upload the photo to.