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 step | JPEG | PNG | What it stands for |
|---|---|---|---|
| Straight file copy (control) | ✓ kept | ✓ kept | No processing at all — proves the measurement itself is sound |
| Pillow, saved again | ✕ stripped | ✕ stripped | The default in most Python image pipelines and batch scripts |
| Pillow, resized then saved | ✕ stripped | ✕ stripped | How thumbnails and bulk resizes are normally produced |
| Pillow, recompressed | ✕ stripped | ✕ stripped | Re-saving a JPEG to cut file size |
| Pillow, passing xmp back on save | ✓ kept | ✕ stripped | Same library, one extra argument — which is what makes this avoidable |
| macOS sips, resized | ✓ kept | ✕ stripped | Ships with macOS; Preview's export and Finder's batch resize sit on the same plumbing |
| macOS sips, format change | ✓ kept | ✕ stripped | Converting between PNG and JPEG |
| ffmpeg, re-encoded | ✕ stripped | ✕ stripped | The engine inside many asset pipelines and transcoding services |
| Squoosh (squoosh.app) (browser-tested) | ✕ stripped | ✕ stripped | Google'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
- 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.
- 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.
- 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.pySquoosh 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 oxiPNGThe 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.