The same cleaner, in a shell.
One JavaScript file bundled from the parsers this site runs, for Node 20 or newer. It reads and writes on your own disk and speaks to nothing else.
curl -O https://filesanity.com/cli/filesanity.mjsone file, 47 kB, no install stepnode filesanity.mjs photo.jpgwrites photo-clean.jpg beside itnode filesanity.mjs --out clean/ ./outboxa folder in, the same shape outnode filesanity.mjs --inspect --json report.pdfread only, one JSON line per filenode filesanity.mjs --keep exif,iptc *.jpga policy: keep those kinds, remove the rest
Five switches.
--out DIR writes the clean files under a folder, keeping the shape of what came in. Without it each clean file lands beside its original with a "-clean" suffix.
--keep a,b,c is the policy from the batch page, by kind: exif, xmp, iptc, com, text, exif-png, time, core, app, custom, thumbnail, info.
--inspect reads and reports, writes nothing. --json prints one JSON object per file, the same report the page shows. --quiet prints only errors.
Exit code 1 if any file was refused, 2 for a usage error. The source is the published parsers; the bundle is built from them at every release.
A server, not a shell?
The same handler runs as an API you host yourself, on a Cloudflare Worker or a Node process.