You migrate a CMS, change a CDN path, or let an old domain lapse — and suddenly every image on the site returns 404. Backups? Not always. But there's a good chance those files still exist in a public web archive: the Internet Archive's Wayback Machine or Common Crawl.
Getting them back one by one through the Wayback calendar is painful. In this tutorial I'll show how the recovery works under the hood, and how to do it in bulk with an open-source CLI I wrote: wayback-image-recovery.
Why manual recovery doesn't scale
A few gotchas show up quickly:
- The Wayback UI wraps captures in HTML. You want the original file, not the page with the toolbar.
- The newest capture can be fake. Many captures are soft-404 error pages saved with HTTP 200.
- Duplicates everywhere. The same logo lives at dozens of URLs.
- Wayback doesn't have everything. A file missing there may still be in Common Crawl.
Step 1: Ask the CDX API what exists
The Wayback Machine exposes a CDX index. For one URL you can request the latest capture:
https://web.archive.org/cdx/search/cdx?url=example.com/images/logo.png&output=json&sort=reverse&limit=1&filter=statuscode:200
For a whole domain you can list unique image URLs with matchType=domain, a mimetype:image/.* filter, and collapse=urlkey.
Gotcha: collapse=urlkey keeps the first row per URL, and rows are oldest-first. So the listing is good for discovery, but you must re-query each URL with sort=reverse&limit=1 (latest) or sort=closest&closest=20200101 (nearest to a date) to get the capture you actually want.
Step 2: Download the original bytes
Take the capture timestamp and add the id_ modifier:
https://web.archive.org/web/20210314120000id_/https://example.com/images/logo.png
id_ returns the raw archived bytes with no rewriting or toolbar.
Step 3: Validate before you save
Don't trust the status code. Check that the response isn't HTML, that the magic bytes match an image type, and that the file isn't suspiciously small or truncated. Then hash it (SHA-256) so identical files are stored once.
Step 4: Fall back to Common Crawl
If Wayback has nothing usable, query Common Crawl's index for the URL. A hit gives you a WARC filename, offset and length — and an HTTP Range request fetches only that record instead of a multi-gigabyte file.
Doing all of this with one command
wayback-image-recovery wraps these steps into a resumable pipeline.
Install (Python 3.9+):
pip install "git+https://github.com/mohamd764/wayback-image-recovery.git"
Recover every archived image under a domain:
wir recover --domain example.com --output ./recovered
Or a list of URLs, preferring captures close to a date:
wir recover urls.txt --closest 2020-01-01 --output ./recovered
Or a CSV export of broken links from your SEO crawler (a url, image_url or src column):
wir recover --csv broken-images.csv --min-bytes 2048
Files keep their original host and path, so putting them back on the server is straightforward. Each run writes:
-
manifest.csv/manifest.json— one row per URL: source, snapshot timestamp, status, sha256, path, bytes, MIME type, error -
manifest.jsonl— an append-only log, so re-running the same command skips files already recovered
A run summary looks like:
Processed 4 URL(s)
recovered=2 duplicate=1 skipped=0 not_found=1 invalid=0 error=0
not_found is normal — archives don't have everything. Use --strict in CI if you want any miss to fail the job.
Be polite to the archives
The Internet Archive and Common Crawl are free public resources. Keep concurrency low, respect rate limits, and only recover content you have rights to. The tool never crawls the live site; it only reads the archives.
Wrap-up
The key ideas: discover with CDX, re-resolve each URL to the right capture, download with id_, validate and dedupe, and fall back to Common Crawl WARC range requests. You can implement that yourself — or use the tool:
👉 github.com/mohamd764/wayback-image-recovery (MIT, tested in CI)
If it saves you a migration headache, a ⭐ helps others find it, and issues/PRs are welcome.
Top comments (0)