Which tools strip the tag

Amazon reads contains-synthetic-performer from XMP dc:subject at upload time, so a tag some processing step quietly dropped is worth exactly as much as no tag at all. Platform and consultancy guidance says “some systems remove embedded metadata during export” — without naming which. So we measured it.

Not one of the 8 processing steps kept the tag on both formats. 5 lost it on JPEG and PNG alike, and the remaining 3 held on to it in JPEG only to drop it in PNG. The most ordinary step of all — re-saving through a standard imaging library — is among the 5.

Processing stepJPEGPNGWhat it stands for
Straight file copy (control)✓ kept✓ keptNo processing at all — proves the measurement itself is sound
Pillow, saved again✕ stripped✕ strippedThe default in most Python image pipelines and batch scripts
Pillow, resized then saved✕ stripped✕ strippedHow thumbnails and bulk resizes are normally produced
Pillow, recompressed✕ stripped✕ strippedRe-saving a JPEG to cut file size
Pillow, passing xmp back on save✓ kept✕ strippedSame library, one extra argument — which is what makes this avoidable
macOS sips, resized✓ kept✕ strippedShips with macOS; Preview's export and Finder's batch resize sit on the same plumbing
macOS sips, format change✓ kept✕ strippedConverting between PNG and JPEG
ffmpeg, re-encoded✕ stripped✕ strippedThe engine inside many asset pipelines and transcoding services
Squoosh (squoosh.app) (browser-tested)✕ stripped✕ strippedGoogle's in-browser compressor, on its mozJPEG and OxiPNG defaults
Canva round trip (hand-tested)✕ stripped
JPEG in → PNG out
Imported and downloaded again. The XMP block is not deleted — Canva's own packet replaces it, so the file still looks like it carries metadata
WeChat desktop, File Transfer (hand-tested)✓ kept
file transfer, JPEG
Computer to computer via 文件传输助手, which offers no original-size option. Arrives byte-for-byte identical
WeChat mobile, 原图 ticked (hand-tested)✓ kept
file transfer, JPEG
Phone to desktop with the original-size box ticked. Byte-for-byte identical again — the file is passed through, not processed
WeChat mobile, 原图 not ticked (hand-tested)✕ stripped
re-encoded, JPEG
The default when sending a photo from a phone. Resized to 2293×1280 and re-encoded to 41% of the original size; the XMP packet is gone entirely

Three things worth taking away

  1. Re-saving is enough to lose it. No cropping, no compression setting, no export dialogue — simply opening and saving a file through a normal imaging library drops the XMP packet. Anything running images through a script is a suspect.
  2. PNG fares worse than JPEG. Every step that managed to preserve the tag on JPEG still lost it on PNG. If a listing image can be either, JPEG is the safer carrier — which is also what Amazon prefers.
  3. It is avoidable, not inevitable. The same library that drops the tag by default keeps it when the XMP block is handed back explicitly on save. Tools lose metadata because nobody asked them to keep it, not because it cannot be done.

A file can still carry metadata and fail anyway

Canva turned out not to delete anything. The exported file still has an XMP packet — it is just Canva's own, describing the Canva document, and the compliance tag that used to sit in dc:subject is not in it. A quick sanity check of the form “does this file have metadata?” passes cleanly while the thing Amazon actually reads has gone.

This is why a checker has to report three states rather than two: tag present, metadata present but no tag, and nothing at all. The middle one is the case that looks fine and is not.

Worth knowing if you also burn in a visible label: it survives, because it is pixels. The image comes back out of Canva still reading “AI-generated person” in the corner while the machine-readable tag is gone — reassuring to look at, and wrong.

Moving a file is not the same as processing it

WeChat gives the cleanest demonstration on this page, because the same app in the same action goes both ways depending on one checkbox. Sent from a phone with 原图 (original size) ticked, the file arrives byte-for-byte identical — same SHA-256, same 2752×1536, tag intact. Sent with the boxunticked, which is what happens by default, it arrives resized to 2293×1280 at 41% of the original weight, with the XMP packet gone completely.

Nothing about WeChat is special here. It kept the tag when it passed the file along and destroyed it when it re-encoded the image, which is the same line every other row falls on. So the useful question about any step is not which app it is, but does it re-encode the image? Compressing, resizing, converting, opening in an editor and saving — all re-encode, and all of them lost the tag here. Copying, zipping, sending as a file — none do, and the bytes come out unchanged.

If you send creative over WeChat, tick 原图. The default path silently strips the tag, and the image looks completely normal afterwards — including any visible label burned into the pixels, which survives the trip while the machine-readable tag does not.

What this means before you upload

Tag late and verify last. If tagging happens before retouching, resizing or compression, assume the tag may not have survived to Seller Central. Drop the final file into the checker — the one you are actually about to upload, not the master it came from.

Check my files →

Method

Each step starts from a fresh 1200×1200 image tagged with this site's own writer, runs through one processing step, and is then read back twice — once by our reader, once by Pillow's independent XMP parser. Rows where the two disagreed would be flagged rather than published; none did.

A pass-through copy runs as a control. If it ever reported the tag as missing, the harness would be broken and every other row void — it passed, on both formats.

python3 tools/metadata-strip-test.py

Squoosh runs in the browser, so a script cannot reach it. That row was measured by driving a real Chrome instead — upload, switch encoder, download, read back. The encoder switch is confirmed from the download filename rather than the dropdown's reported value, because a controlled select can claim a setting it never applied; the first attempt silently produced a JPEG while claiming to test PNG, and that run was discarded.

python3 tools/squoosh-strip-test.py tagged-sample.png oxiPNG

The script is in the repository; run it and you should reproduce this table. Tested 2026-07-28 on macOS 26.2, Pillow 12.1.1, ffmpeg 8.0.1, Node v25.6.0.

What is not covered. These are scriptable steps. Photoshop, Lightroom, Canva, in-house DAM systems and agency portals need accounts or a GUI, so they are not in the table — their absence is not a pass. If you have measured one, the method above is the same one to use.

Results describe the specific tool versions listed above. Behaviour can change between releases.