Search Console (Jun 4 – Sep 3) shows the page ranking on the first results page for "content credentials" queries while converting badly: "ai credentials remover" at 113 impressions and 0.88% CTR from position 6.7, "remove content credentials from image online" at 2.15% from position 5.0, "remove ai content credentials from image" at 0% from position 7.8. The title led with "EXIF metadata", a phrase that appears in none of the top queries, so the snippet never matched the intent behind the impressions. SEO - Title, description and H1 rebuilt around "remove content credentials from an image"; EXIF kept as a secondary term. - Added a how-to section and a nine-question FAQ answering the question queries that had no content behind them, including the LinkedIn AI label and the Instagram AI tag. - Structured data as an @graph: WebSite (alternateName "Untrace AI" for the unserved brand query), Organization, WebApplication, HowTo, FAQPage. - Fixed sitemap.xml, which pointed at /untrace/ — a URL that does not exist. - Regenerated the Open Graph image to match the new design. Design - Vendored the design system at src/tokens.css and composed the app from it. The old styling broke most of its rules: gradients, font weights 800 and 900, raw #2563eb, Inter, and emoji as the only status signal. - Reworked the tool into a Scan / Review / Download flow that lists what it found before changing anything, with the primary action pinned within thumb reach on small screens. - Dark by default with a light theme, applied before first paint so the page never flashes the wrong surface. - Replaced the floating donation widget, which painted an off-token circle over the page and covered the mobile action bar, with a footer link. Structure - Moved detection into src/lib/metadata.js and removal into src/lib/clean.js; the canvas callbacks are now a promise chain. - Dropped Tailwind and PostCSS. Both were configured twice, and no Tailwind utility was used. Stylesheet is 6.2 kB gzipped with the whole system in it. Fixes - The stepper never advanced: stepState(index) read `current` from the closure, which Svelte 4 cannot track as a template dependency. - The cleaner's fallback returned the original, uncleaned file while the UI reported "All EXIF metadata removed". It now reports the failure instead. Verified against a JPEG carrying EXIF, GPS, XMP and an APP11 JUMBF C2PA manifest: the output retains only APP0 and the sRGB ICC profile, with every provenance marker gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018pRSdR57Ze9M2meDfYZgYE
81 lines
2.9 KiB
Markdown
81 lines
2.9 KiB
Markdown
# Untrace
|
|
|
|
**Remove content credentials from an image.**
|
|
|
|
Untrace strips C2PA content credentials, AI generation tags, GPS coordinates
|
|
and EXIF metadata from a photo. It runs entirely in the browser — the file is
|
|
read and rewritten in the tab, never uploaded.
|
|
|
|
<https://untrace.realbrain.cc/>
|
|
|
|
## What it removes
|
|
|
|
| | |
|
|
|---|---|
|
|
| C2PA content credentials | Manifests, claims, assertions and signatures from the Content Authenticity Initiative |
|
|
| AI generation tags | ChatGPT, DALL·E, Midjourney, Stable Diffusion, Adobe Firefly, Google Imagen |
|
|
| JUMBF containers | The APP11 and APP2 boxes that carry provenance inside a JPEG |
|
|
| GPS location | Latitude, longitude, altitude, bearing and their timestamp |
|
|
| Camera and device | Make, model, lens, serial numbers, exposure and shooting settings |
|
|
| Timestamps | When the photo was taken, digitised and last modified |
|
|
| XMP and IPTC | Creator names, captions, keywords, copyright, editing history |
|
|
| Comments and thumbnails | User comments, maker notes, embedded previews |
|
|
| PNG text chunks | tEXt, iTXt and zTXt blocks, including generation prompts |
|
|
|
|
Supported input: JPEG, PNG, TIFF, HEIC, AVIF. Output is JPEG, or PNG when the
|
|
original was a small PNG.
|
|
|
|
## How it works
|
|
|
|
Detection and removal are two separate passes.
|
|
|
|
**Detection** (`src/lib/metadata.js`) reads the file twice: once through
|
|
[exifr](https://github.com/MikeKovarik/exifr) for structured segments, and once
|
|
as raw bytes to find C2PA strings and JUMBF boxes that exifr does not surface.
|
|
The results are merged and bucketed into named sections, then turned into the
|
|
findings list the review step renders.
|
|
|
|
**Removal** (`src/lib/clean.js`) decodes the image to pixels on a canvas and
|
|
re-encodes it. Nothing carries over, so every metadata container is dropped at
|
|
once rather than deleting known tags one by one and leaving the rest behind.
|
|
The output is then re-read to confirm it is clean; if anything survived, a
|
|
second pass forces JPEG on a white matte.
|
|
|
|
If the browser cannot decode or re-encode the file, the original bytes are
|
|
returned and the interface says so — it never reports a clean that did not
|
|
happen.
|
|
|
|
## Design
|
|
|
|
The interface follows the
|
|
[RealBrain Design System](https://realbrain.cc/design-system/) v2.0. Tokens are
|
|
vendored at `src/tokens.css`; refresh with:
|
|
|
|
```bash
|
|
curl -o src/tokens.css https://realbrain.cc/design-system/tokens.css
|
|
```
|
|
|
|
`AGENTS.md` carries the rules, the self-check commands, and this repository's
|
|
open token proposals. Read it before touching any CSS.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev # vite dev server
|
|
npm run build # production build to dist/
|
|
npm run preview # serve the build
|
|
```
|
|
|
|
Stack: Svelte 4, Vite 5, exifr. No CSS framework — the design system is plain
|
|
CSS.
|
|
|
|
## Who it is for
|
|
|
|
Journalists protecting sources, activists maintaining anonymity, photographers
|
|
selling stock, and anyone who would rather a photo not carry its own history.
|
|
|
|
## License
|
|
|
|
MIT.
|